org.socialsignin.spring.data.dynamodb.repository.query.AbstractDynamoDBQuery.java Source code

Java tutorial

Introduction

Here is the source code for org.socialsignin.spring.data.dynamodb.repository.query.AbstractDynamoDBQuery.java

Source

/*
 * Copyright 2013 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.socialsignin.spring.data.dynamodb.repository.query;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.socialsignin.spring.data.dynamodb.core.DynamoDBOperations;
import org.socialsignin.spring.data.dynamodb.query.Query;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;

/**
 * @author Michael Lavelle
 */
public abstract class AbstractDynamoDBQuery<T, ID extends Serializable> implements RepositoryQuery {

    protected final DynamoDBOperations dynamoDBOperations;
    private final DynamoDBQueryMethod<T, ID> method;

    public AbstractDynamoDBQuery(DynamoDBOperations dynamoDBOperations, DynamoDBQueryMethod<T, ID> method) {
        this.dynamoDBOperations = dynamoDBOperations;
        this.method = method;
    }

    protected QueryExecution<T, ID> getExecution() {
        if (method.isCollectionQuery() && !isSingleEntityResultsRestriction()) {
            return new CollectionExecution();
        } else if (method.isSliceQuery() && !isSingleEntityResultsRestriction()) {
            return new SlicedExecution(method.getParameters());
        } else if (method.isPageQuery() && !isSingleEntityResultsRestriction()) {
            return new PagedExecution(method.getParameters());
        } else if (method.isModifyingQuery()) {
            throw new UnsupportedOperationException("Modifying queries not yet supported");
        } else if (isSingleEntityResultsRestriction()) {
            return new SingleEntityLimitedExecution();
        } else {
            return new SingleEntityExecution();
        }
    }

    protected abstract Query<T> doCreateQuery(Object[] values);

    protected abstract Query<Long> doCreateCountQuery(Object[] values, boolean pageQuery);

    protected abstract boolean isCountQuery();

    protected abstract Integer getResultsRestrictionIfApplicable();

    protected abstract boolean isSingleEntityResultsRestriction();

    protected Query<T> doCreateQueryWithPermissions(Object values[]) {
        Query<T> query = doCreateQuery(values);
        query.setScanEnabled(method.isScanEnabled());
        return query;
    }

    protected Query<Long> doCreateCountQueryWithPermissions(Object values[], boolean pageQuery) {
        Query<Long> query = doCreateCountQuery(values, pageQuery);
        query.setScanCountEnabled(method.isScanCountEnabled());
        return query;
    }

    private interface QueryExecution<T, ID extends Serializable> {
        public Object execute(AbstractDynamoDBQuery<T, ID> query, Object[] values);
    }

    class CollectionExecution implements QueryExecution<T, ID> {

        @Override
        public Object execute(AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] values) {
            Query<T> query = dynamoDBQuery.doCreateQueryWithPermissions(values);
            if (getResultsRestrictionIfApplicable() != null) {
                return restrictMaxResultsIfNecessary(query.getResultList().iterator());
            } else
                return query.getResultList();
        }

        private List<T> restrictMaxResultsIfNecessary(Iterator<T> iterator) {
            int processed = 0;
            List<T> resultsPage = new ArrayList<T>();
            while (iterator.hasNext() && processed < getResultsRestrictionIfApplicable()) {
                resultsPage.add(iterator.next());
                processed++;
            }
            return resultsPage;
        }

    }

    /**
     * Executes the {@link AbstractStringBasedJpaQuery} to return a
     * {@link org.springframework.data.domain.Page} of entities.
     */
    class PagedExecution implements QueryExecution<T, ID> {

        private final Parameters<?, ?> parameters;

        public PagedExecution(Parameters<?, ?> parameters) {

            this.parameters = parameters;
        }

        private int scanThroughResults(Iterator<T> iterator, int resultsToScan) {
            int processed = 0;
            while (iterator.hasNext() && processed < resultsToScan) {
                iterator.next();
                processed++;
            }
            return processed;
        }

        private List<T> readPageOfResultsRestrictMaxResultsIfNecessary(Iterator<T> iterator, int pageSize) {
            int processed = 0;
            int toProcess = getResultsRestrictionIfApplicable() != null
                    ? Math.min(pageSize, getResultsRestrictionIfApplicable())
                    : pageSize;
            List<T> resultsPage = new ArrayList<T>();
            while (iterator.hasNext() && processed < toProcess) {
                resultsPage.add(iterator.next());
                processed++;
            }
            return resultsPage;
        }

        @Override
        public Object execute(AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] values) {

            ParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
            Pageable pageable = accessor.getPageable();
            Query<T> query = dynamoDBQuery.doCreateQueryWithPermissions(values);

            List<T> results = query.getResultList();
            return createPage(results, pageable, dynamoDBQuery, values);
        }

        private Page<T> createPage(List<T> allResults, Pageable pageable,
                AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] values) {

            Iterator<T> iterator = allResults.iterator();
            int processedCount = 0;
            if (pageable.getOffset() > 0) {
                processedCount = scanThroughResults(iterator, pageable.getOffset());
                if (processedCount < pageable.getOffset())
                    return new PageImpl<T>(new ArrayList<T>());
            }
            List<T> results = readPageOfResultsRestrictMaxResultsIfNecessary(iterator, pageable.getPageSize());

            Query<Long> countQuery = dynamoDBQuery.doCreateCountQueryWithPermissions(values, true);
            long count = countQuery.getSingleResult();

            if (getResultsRestrictionIfApplicable() != null) {
                count = Math.min(count, getResultsRestrictionIfApplicable());
            }

            return new PageImpl<T>(results, pageable, count);

        }
    }

    class SlicedExecution implements QueryExecution<T, ID> {

        private final Parameters<?, ?> parameters;

        public SlicedExecution(Parameters<?, ?> parameters) {

            this.parameters = parameters;
        }

        private int scanThroughResults(Iterator<T> iterator, int resultsToScan) {
            int processed = 0;
            while (iterator.hasNext() && processed < resultsToScan) {
                iterator.next();
                processed++;
            }
            return processed;
        }

        private List<T> readPageOfResultsRestrictMaxResultsIfNecessary(Iterator<T> iterator, int pageSize) {
            int processed = 0;
            int toProcess = getResultsRestrictionIfApplicable() != null
                    ? Math.min(pageSize, getResultsRestrictionIfApplicable())
                    : pageSize;

            List<T> resultsPage = new ArrayList<T>();
            while (iterator.hasNext() && processed < toProcess) {
                resultsPage.add(iterator.next());
                processed++;
            }
            return resultsPage;
        }

        @Override
        public Object execute(AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] values) {

            ParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
            Pageable pageable = accessor.getPageable();
            Query<T> query = dynamoDBQuery.doCreateQueryWithPermissions(values);
            List<T> results = query.getResultList();
            return createSlice(results, pageable);
        }

        private Slice<T> createSlice(List<T> allResults, Pageable pageable) {

            Iterator<T> iterator = allResults.iterator();
            int processedCount = 0;
            if (pageable.getOffset() > 0) {
                processedCount = scanThroughResults(iterator, pageable.getOffset());
                if (processedCount < pageable.getOffset())
                    return new SliceImpl<T>(new ArrayList<T>());
            }
            List<T> results = readPageOfResultsRestrictMaxResultsIfNecessary(iterator, pageable.getPageSize());
            // Scan ahead to retrieve the next page count
            boolean hasMoreResults = scanThroughResults(iterator, 1) > 0;
            if (getResultsRestrictionIfApplicable() != null
                    && getResultsRestrictionIfApplicable().intValue() <= results.size())
                hasMoreResults = false;
            return new SliceImpl<T>(results, pageable, hasMoreResults);
        }
    }

    class SingleEntityExecution implements QueryExecution<T, ID> {

        @Override
        public Object execute(AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] values) {
            if (isCountQuery()) {
                return dynamoDBQuery.doCreateCountQueryWithPermissions(values, false).getSingleResult();
            } else {
                return dynamoDBQuery.doCreateQueryWithPermissions(values).getSingleResult();
            }

        }
    }

    class SingleEntityLimitedExecution implements QueryExecution<T, ID> {

        @Override
        public Object execute(AbstractDynamoDBQuery<T, ID> dynamoDBQuery, Object[] values) {
            if (isCountQuery()) {
                return dynamoDBQuery.doCreateCountQueryWithPermissions(values, false).getSingleResult();
            } else {
                List<T> resultList = dynamoDBQuery.doCreateQueryWithPermissions(values).getResultList();
                return resultList.size() == 0 ? null : resultList.get(0);

            }

        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.springframework.data.repository.query.RepositoryQuery#execute(java
     * .lang.Object[])
     */
    public Object execute(Object[] parameters) {

        return getExecution().execute(this, parameters);
    }

    @Override
    public DynamoDBQueryMethod<T, ID> getQueryMethod() {
        return this.method;
    }

}