/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.master.impl; import java.util.Iterator; import java.util.NoSuchElementException; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.master.AbstractDocument; import com.opengamma.master.AbstractMaster; import com.opengamma.master.AbstractSearchRequest; import com.opengamma.master.AbstractSearchResult; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.paging.PagingRequest; /** * An iterator that searches a config master as an iterator. * <p> * Large systems may store a large amount of data in each master. * A simple search request that pulls back the entire database is unrealistic. * This remote iterator allows the database to be queried in a consistent way remotely. * * @param <D> the type of the document * @param <M> the type of the master * @param <R> the type of the search request */ public abstract class AbstractSearchIterator<D extends AbstractDocument, M extends AbstractMaster<D>, R extends AbstractSearchRequest> implements Iterator<D> { /** * The master that is being used. */ private M _master; /** * The request object that is being used. */ private final R _request; /** * The last result object. */ private AbstractSearchResult<D> _currentBatch; /** * The index of the next object within the batch result. */ private int _currentBatchIndex; /** * The current document, null if not fetched, at end or removed. */ private D _current; /** * The overall index of the last retrieved object. */ private int _overallIndex; /** * Creates an instance based on a request. * <p> * The request will be altered during the iteration. * * @param master the underlying master, not null * @param request the request object, not null */ protected AbstractSearchIterator(M master, R request) { ArgumentChecker.notNull(master, "master"); ArgumentChecker.notNull(request, "request"); _master = master; _request = request; } //------------------------------------------------------------------------- @Override public boolean hasNext() { if (_currentBatch == null || _currentBatchIndex >= _currentBatch.getDocuments().size()) { doFetch(); } return (_currentBatch != null && _currentBatchIndex < _currentBatch.getDocuments().size()); } @Override public D next() { if (hasNext() == false) { throw new NoSuchElementException("No more elements found"); } return doNext(); } /** * Removes the last seen document. */ @Override public void remove() { if (_current == null) { throw new IllegalStateException(); } } /** * Gets the overall index of the next entry. * <p> * This number may skip if a bad entry is found. * * @return the overall index of the next entry, 0 if next() not called yet */ public int nextIndex() { return _overallIndex; } private void doFetch() { try { // try to fetch a batch of 20 documents _request.setPagingRequest(PagingRequest.ofIndex(_overallIndex, 20)); _currentBatch = doSearch(_request); } catch (RuntimeException ex) { doFetchOne(ex); } // ensure same vc for whole iterator _request.setVersionCorrection(_currentBatch.getVersionCorrection()); // check results if (_currentBatch.getPaging().getFirstItem() < _overallIndex) { _currentBatchIndex = (_overallIndex - _currentBatch.getPaging().getFirstItem()); } else { _currentBatchIndex = 0; } } /** * Fetches the next one document. * * @param ex the original exception, not null */ private void doFetchOne(RuntimeException ex) { // try to load just the next document int maxFailures = 5; if (_currentBatch != null) { maxFailures = _currentBatch.getPaging().getTotalItems() - _overallIndex; // if we have results, use maximum count maxFailures = Math.min(maxFailures, 20); } while (maxFailures > 0) { try { _request.setPagingRequest(PagingRequest.ofIndex(_overallIndex, 1)); _currentBatch = doSearch(_request); return; } catch (RuntimeException ex2) { _overallIndex++; // abandon this document maxFailures--; } } throw new OpenGammaRuntimeException("Multiple documents failed to load", ex); } private D doNext() { _current = _currentBatch.getDocuments().get(_currentBatchIndex); _currentBatchIndex++; _overallIndex++; return _current; } /** * Performs the search on the master. * * @param request the request to send, not null * @return the search result, not null * @throws RuntimeException if an error occurs */ protected abstract AbstractSearchResult<D> doSearch(R request); //----------------------------------------------------------------------- /** * Gets the underlying master. * * @return the master, not null */ public M getMaster() { return _master; } /** * Gets the request object that is being used. * * @return the request, not null */ public R getRequest() { return _request; } }