Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2011-2014 Amazon Technologies, Inc.
   *
   * 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://aws.amazon.com/apache2.0
   *
  * This file 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 com.amazonaws.services.dynamodbv2.datamodeling;
 
 import java.util.List;
 
Unmodifiable list supporting paginated result sets from Amazon DynamoDB.

Pages of results are fetched lazily from DynamoDB as they are needed. Some methods, such as size() and toArray(), require fetching the entire result set eagerly. See the javadoc of individual methods for details on which are lazy.

Parameters:
<T> The domain object type stored in this list.
 
 public abstract class PaginatedList<T> implements List<T> {
 
     private static final String UNMODIFIABLE_MESSAGE = "This is an unmodifiable list";
     
     private static final String ITERATION_ONLY_UNSUPPORTED_OPERATION_MESSAGE = " is not supported when using ITERATION_ONLY configuration.";

    
Reference to the DynamoDB mapper for marshalling DynamoDB attributes back into objects
 
     protected final DynamoDBMapper mapper;

    
The class annotated with DynamoDB tags declaring how to load/store objects into DynamoDB
 
     protected final Class<T> clazz;

    
The client for working with DynamoDB
 
     protected final AmazonDynamoDB dynamo;

    
Tracks if all results have been loaded yet or not
 
     protected boolean allResultsLoaded = false;    

    
All currently loaded results for this list. In ITERATION_ONLY mode, this list will at most keep one page of the loaded results, and all previous results will be cleared from the memory.
 
     protected final List<T> allResults;
    
    
Lazily loaded next results waiting to be added into allResults
 
     protected final List<T> nextResults = new LinkedList<T>();
    
    
The pagination loading strategy for this paginated list
 
     private final PaginationLoadingStrategy paginationLoadingStrategy;
    
    
Keeps track on whether an iterator of the list has been retrieved. Only updated and checked when the list is in ITERATION_ONLY mode.
 
     private boolean iterationStarted = false;

    
Constructs a PaginatedList instance using the default PaginationLoadingStrategy
 
     public PaginatedList(DynamoDBMapper mapperClass<T> clazzAmazonDynamoDB dynamo) {
         this(mapperclazzdynamonull);
     }
    
    
Constructs a PaginatedList instance.

Parameters:
mapper The mapper for marshalling DynamoDB attributes into objects.
clazz The class of the annotated model.
dynamo The DynamoDB client for making low-level request calls.
paginationLoadingStrategy The strategy used for loading paginated results. Caller has to explicitly set this parameter, since the DynamoDBMapperConfig set in the mapper is not accessible here. If null value is provided, LAZY_LOADING will be set by default.
    public PaginatedList(DynamoDBMapper mapperClass<T> clazzAmazonDynamoDB dynamoPaginationLoadingStrategy paginationLoadingStrategy) {
        this. = mapper;
        this. = clazz;
        this. = dynamo;
        this. = paginationLoadingStrategy == null ?
                . : paginationLoadingStrategy;
        this. = new ArrayList<T>();
        
        // Ideally, we should eagerly load all results here as soon as EAGER_LOADING is configured.
        // But the implementation of loadAllResults() relies on a fully initialized sub-class object.
        // So we have to do this in each sub-class constructor.
    }

    
Eagerly loads all results for this list.

Not supported in ITERATION_ONLY mode.

    public synchronized void loadAllResults() {
        checkUnsupportedOperationForIterationOnlyMode("loadAllResults()");
        
        if (  )
            return;
        while ( nextResultsAvailable() ) {
            // Keep all loaded results
            moveNextResults(false);
        }
         = true;
    }
    
    
Returns whether there are more results available not yet included in the allResults member field. These could already have been fetched and are sitting in the nextResults buffer, or they could be fetched from the service opportunistically at the time this method is called. A return value of true guarantees that nextResults is non-empty.
    private boolean nextResultsAvailable() {
        return !.isEmpty() || loadNextResults();
    }

    
Attempts to load the next batch of results, if there are any, into the nextResults buffer. Returns whether there were any results to load. A return value of true guarantees that nextResults had items added to it.
    private synchronized boolean loadNextResults() {
        if ( atEndOfResults() )
            return false;
        do {
            .addAll(fetchNextPage());
        } while ( !atEndOfResults() && .isEmpty() );
        return !.isEmpty();
    }

    
Moves the contents of the nextResults buffer into allResults and resets the buffer.

Parameters:
clearPreviousResults Whether it should clear previous results in allResults field.
    private void moveNextResults(boolean clearPreviousResults) {
        if (clearPreviousResults) {
            .clear();
        }
        .addAll();
        .clear();
    }
    
    
Fetches the next page of results (which may be empty) and returns any items found.
    protected abstract List<T> fetchNextPage();
    
    
Returns whether we have reached the end of the result set.
    protected abstract boolean atEndOfResults();

    
Returns an iterator over this list that lazily initializes results as necessary.

If it configured with ITERARTION_ONLY mode, then the iterator could be only retrieved once, and any previously loaded results will be cleared in the memory during the iteration.

    @Override
    public Iterator<T> iterator() {
    }
    
    private class PaginatedListIterator implements Iterator<T> {
        
Whether this iterator is constructed by a PaginatedList in ITERATION_ONLY mode.
        private final boolean iterationOnly;
        
        
A hard copy of the allResults list to prevent ConcurrentModificationExceptions. Only needed when the list is not in ITERNATION_ONLY mode.
        private final List<T> allResultsCopy;
        
        private Iterator<T> innerIterator;
        
        private int pos = 0;
        
        public PaginatedListIterator(boolean iterationOnly) {
            this. = iterationOnly;
            
            if (iterationOnly) {
                synchronized (PaginatedList.this) {
                    if () {
                        throw new UnsupportedOperationException("The list could only be iterated once in ITERATION_ONLY mode.");
                    }
                     = true;
                }
                
                 = null// not needed for ITERATION_ONLY mode
                 = .iterator();
            }
            else {
                /*
                 * We make a copy of the allResults list to iterate over in order to
                 * avoid ConcurrentModificationExceptions caused by other methods
                 * loading more results into the list while someone iterates over it.
                 * This is a more severe problem than it might seem, because even
                 * innocuous-seeming operations such as contains() can modify the
                 * underlying result set.
                 */
                 = new ArrayList<T>();
                .addAll();        
                 = .iterator();
            }
        }
        
        @Override
        public boolean hasNext() {
            return .hasNext() || nextResultsAvailable();
        }
        @Override
        public T next() {
            if ( !.hasNext() ) {
                /*
                 * We need to immediately fetch more results from the service,
                 * if 
                 *   -- it's in ITERATION_ONLY mode (which means innerIterator
                 *      is always pointing at the "real" list of loaded results)
                 *   OR it's not in ITERATION_ONLY and our private copy of the
                 *      result list is already up to date with the full one.
                 */
                if ( 
                        || .size() == .size() ) {
                    if ( !nextResultsAvailable() ) {
                        throw new NoSuchElementException();
                    }
                    /* Clear previous results if it's in ITERATION_ONLY mode */
                    boolean clearPreviousResults = ;
                    moveNextResults(clearPreviousResults);
                } 
                
                if (  ) {
                    /*
                     * allResults has been replaced with the latest page of results.
                     */
                     = .iterator();
                } else {
                    /*
                     * Update our private results copy, and then update the inner iterator
                     */
                    if ( .size() > .size() )
                        .addAll(.subList(.size(), .size()));
                    
                     = .listIterator();
                }
            }
            
            ++;
            return .next();
        }
        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
        
    }

    
Returns whether the collection is empty. At most one (non-empty) page of results is loaded to make the check.

Not supported in ITERATION_ONLY mode.

    @Override
    public boolean isEmpty() {
        
        return !iterator().hasNext();
    }

    
Returns the Nth element of the list. Results are loaded until N elements are present, if necessary.

Not supported in ITERATION_ONLY mode.

    @Override
    public T get(int n) {
        checkUnsupportedOperationForIterationOnlyMode("get(int n)");
        
        while ( .size() <= n && nextResultsAvailable() ) {
            moveNextResults(false);
        }
        return .get(n);
    }
    
    
Returns whether the collection contains the given element. Results are loaded and checked incrementally until a match is found or the end of the result set is reached.

Not supported in ITERATION_ONLY mode.

    @Override
    public boolean contains(Object arg0) {
        checkUnsupportedOperationForIterationOnlyMode("contains(Object arg0)");
        
        if ( .contains(arg0) )
            return true;
        
        while ( nextResultsAvailable() ) {
            boolean found = .contains(arg0);
            moveNextResults(false);
            if ( found )
                return true;
        }
        return false;
    }

    
Returns a sub-list in the range specified, loading more results as necessary.

Not supported in ITERATION_ONLY mode.

    @Override
    public List<T> subList(int arg0int arg1) {
        checkUnsupportedOperationForIterationOnlyMode("subList(int arg0, int arg1)");
        
        while ( .size() < arg1 && nextResultsAvailable() ) {
            moveNextResults(false);
        }
        
        return Collections.unmodifiableList(.subList(arg0arg1));
    }

    
Returns the first index of the object given in the list. Additional results are loaded incrementally as necessary.

Not supported in ITERATION_ONLY mode.

    @Override
    public int indexOf(Object arg0) {
        checkUnsupportedOperationForIterationOnlyMode("indexOf(Object org0)");
        
        int indexOf = .indexOf(arg0);
        if ( indexOf >= 0 )
            return indexOf;
        while ( nextResultsAvailable() ) {
            indexOf = .indexOf(arg0);
            int size = .size();
            moveNextResults(false);
            if ( indexOf >= 0 )
                return indexOf + size;
        }
        return -1;
    }
    // Operations requiring the entire result set
    
    @Override
    public int size() {
        loadAllResults();
        return .size();
    }
    
    @Override
    public boolean containsAll(Collection<?> arg0) {
        loadAllResults();
        return .containsAll(arg0);
    }
    @Override
    public int lastIndexOf(Object arg0) {
        loadAllResults();
        return .lastIndexOf(arg0);
    }
    @Override
    public Object[] toArray() {
        loadAllResults();
        return .toArray();
    }
    @Override
    public <X> X[] toArray(X[] a) {
        loadAllResults();
        return .toArray(a);
    }
    // Unsupported Operations
    @Override
    public ListIterator<T> listIterator() {
        throw new UnsupportedOperationException("ListIterators are not supported for this list");
    }
    @Override
    public ListIterator<T> listIterator(int arg0) {
        throw new UnsupportedOperationException("ListIterators are not supported for this list");
    }
    @Override
    public boolean remove(Object arg0) {
    }
    @Override
    public T remove(int arg0) {
    }
    @Override
    public boolean removeAll(Collection<?> arg0) {
    }
    @Override
    public boolean retainAll(Collection<?> arg0) {
    }
    @Override
    public T set(int arg0, T arg1) {
    }
    @Override
    public boolean add(T arg0) {
    }
    @Override
    public void add(int arg0, T arg1) {
    }
    @Override
    public boolean addAll(Collection<? extends T> arg0) {
    }
    @Override
    public boolean addAll(int arg0Collection<? extends T> arg1) {
    }
    @Override
    public void clear() {
    }
    
    private void checkUnsupportedOperationForIterationOnlyMode(String methodSignature) {
            throw new UnsupportedOperationException(methodSignature + );
        }
    };
New to GrepCode? Check out our FAQ X