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

org.dbflute.bhv.readable.coins.VirtualUnionPagingBean Maven / Gradle / Ivy

/*
 * Copyright 2014-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.dbflute.bhv.readable.coins;

import java.util.ArrayList;
import java.util.List;

import org.dbflute.cbean.result.PagingResultBean;
import org.dbflute.cbean.result.ResultBeanBuilder;

/**
 * The handler of entity row.
 * @param  The type of identity.
 * @param  The type of mapped result.
 * @author jflute
 * @since 1.1.0 (2014/12/30 Tuesday)
 */
public class VirtualUnionPagingBean {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final List _metaMap = new ArrayList();
    protected int _pageSize;
    protected int _pageNumber;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public VirtualUnionPagingBean(VirtualUnionPagingIdSelector noArgLambda, VirtualUnionPagingDataMapper oneArgLambda) {
        unionAll(noArgLambda, oneArgLambda);
    }

    // ===================================================================================
    //                                                                               Union
    //                                                                               =====
    // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
    // cannot order through all records
    // and no union(), you should remove duplicate records after select manually
    // _/_/_/_/_/_/_/_/_/_/
    public VirtualUnionPagingBean unionAll(VirtualUnionPagingIdSelector noArgLambda,
            VirtualUnionPagingDataMapper oneArgLambda) {
        _metaMap.add(newVirtualUnionPagingMetaInfo(noArgLambda, oneArgLambda));
        return this;
    }

    protected VirtualUnionPagingMeta newVirtualUnionPagingMetaInfo(VirtualUnionPagingIdSelector idSelector,
            VirtualUnionPagingDataMapper dataMapper) {
        return new VirtualUnionPagingMeta(idSelector, dataMapper);
    }

    // ===================================================================================
    //                                                                              Paging
    //                                                                              ======
    public VirtualUnionPagingSelector paging(int pageSize, int pageNumber) {
        if (pageSize < 1) {
            throw new IllegalArgumentException("The pageSize should not be minus or zero: " + pageSize);
        }
        if (pageNumber < 1) {
            throw new IllegalArgumentException("The pageNumber should not be minus or zero: " + pageNumber);
        }
        _pageSize = pageSize;
        _pageNumber = pageNumber;
        return new VirtualUnionPagingSelector() {
            public PagingResultBean selectPage() {
                return doSelectPage();
            }
        };
    }

    protected PagingResultBean doSelectPage() {
        final PagingResultBean page = actuallySelectPage(_pageSize, _pageNumber);
        if (page.getCurrentPageNumber() > 1 && page.isEmpty()) {
            return actuallySelectPage(_pageSize, page.getAllPageCount()); // retry
        }
        return page;
    }

    protected PagingResultBean actuallySelectPage(int pageSize, int pageNumber) {
        final int allRecordCount = prepareIdList();
        final List resultList = new ArrayList();
        final boolean usePaging = pageSize > 0 && pageNumber > 0;
        final int limit = usePaging ? pageSize * pageNumber : -1;
        final int offset = usePaging ? pageSize * (pageNumber - 1) : -1;
        int skippedCount = 0;
        boolean overOffset = false;
        int actualCount = 0;
        for (VirtualUnionPagingMeta meta : _metaMap) {
            final VirtualUnionPagingDataMapper dataMapper = meta.getDataMapper();
            List idList = meta.getIdList();
            if (idList.isEmpty()) {
                continue;
            }
            if (usePaging) {
                if (!overOffset) {
                    final int scheduledSkippedCount = skippedCount + idList.size();
                    if (scheduledSkippedCount < offset) {
                        skippedCount = skippedCount + idList.size();
                        continue;
                    }
                    overOffset = true;
                    idList = filterIdListByOffset(idList, skippedCount, offset);
                    if (idList.isEmpty()) { // re-check
                        continue;
                    }
                }
                idList = filterIdListByLimit(idList, actualCount, limit, offset);
                if (idList.isEmpty()) { // re-check
                    continue;
                }
            }
            final List mappedList = dataMapper.selectMappedList(idList);
            final int mappedSize = mappedList.size();
            assertMappedSizeValidForIdList(idList, mappedSize);
            resultList.addAll(mappedList);
            actualCount = actualCount + mappedSize;
            if (usePaging && actualCount >= limit) {
                break;
            }
        }
        final ResultBeanBuilder builder = new ResultBeanBuilder("UNION_PAGING");
        return builder.buildPagingSimply(pageSize, pageNumber, allRecordCount, resultList);
    }

    protected int prepareIdList() {
        int count = 0;
        for (VirtualUnionPagingMeta meta : _metaMap) {
            final VirtualUnionPagingIdSelector idSelector = meta.getIdSelector();
            final List idList = idSelector.selectIdList();
            meta.setIdList(idList);
            count = count + idList.size();
        }
        return count;
    }

    protected List filterIdListByOffset(List idList, int skippedCount, int offset) {
        return idList.subList(offset - skippedCount, idList.size());
    }

    protected List filterIdListByLimit(List idList, int actualCount, int limit, int offset) {
        final int scheduledCount = actualCount + idList.size();
        final int pageSize = limit - offset; // not use instance variable for independent
        if (scheduledCount > pageSize) { // mean last
            if (actualCount == 0) {
                idList = idList.subList(0, pageSize);
            } else {
                final int remainderSize = pageSize - actualCount;
                idList = remainderSize < idList.size() ? idList.subList(0, remainderSize) : idList;
            }
        }
        return idList;
    }

    protected void assertMappedSizeValidForIdList(List idList, final int mappedSize) {
        if (mappedSize > idList.size()) {
            String msg = "mapped list is over the ID list: " + mappedSize + ", " + idList;
            throw new IllegalStateException(msg);
        }
    }

    // ===================================================================================
    //                                                                        Helper Class
    //                                                                        ============
    public interface VirtualUnionPagingSelector { // not function interface, for chain
        PagingResultBean selectPage();
    }

    public class VirtualUnionPagingMeta {

        protected VirtualUnionPagingIdSelector _idSelector;
        protected VirtualUnionPagingDataMapper _dataMapper;
        protected List _idList; // set later

        public VirtualUnionPagingMeta(VirtualUnionPagingIdSelector idSelector, VirtualUnionPagingDataMapper dataMapper) {
            _idSelector = idSelector;
            _dataMapper = dataMapper;
        }

        public VirtualUnionPagingIdSelector getIdSelector() {
            return _idSelector;
        }

        public void setIdSelector(VirtualUnionPagingIdSelector idSelector) {
            _idSelector = idSelector;
        }

        public VirtualUnionPagingDataMapper getDataMapper() {
            return _dataMapper;
        }

        public void setDataMapper(VirtualUnionPagingDataMapper dataMapper) {
            _dataMapper = dataMapper;
        }

        public List getIdList() {
            return _idList;
        }

        public void setIdList(List idList) {
            _idList = idList;
        }
    }

    @FunctionalInterface
    public interface VirtualUnionPagingIdSelector {
        List selectIdList();
    }

    @FunctionalInterface
    public interface VirtualUnionPagingDataMapper {
        List selectMappedList(List idList);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy