/** * */ package com.ebay.cloud.cms.typsafe.service; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ebay.cloud.cms.typsafe.entity.CMSQuery; import com.ebay.cloud.cms.typsafe.entity.CMSQueryResult; import com.ebay.cloud.cms.typsafe.entity.ICMSEntity; import com.ebay.cloud.cms.typsafe.exception.CMSClientException; import com.google.common.base.Preconditions; /** * * @author liasu * */ public class QueryIterator<T extends ICMSEntity> implements Iterator<T> { private static final Logger logger = LoggerFactory.getLogger(QueryIterator.class); private CMSQuery query; private Integer nextHint; private long[] nextSkip; private long[] nextLimit; private int maxFetch; private List<String> sortOn; private List<String> sortOrder; private String cursorString; private boolean hasMore; private final Class<T> clz; private CMSClientService service; private CMSClientContext context; private LinkedList<T> entities; // // statistics information for the query iteration // // the total count of the entities that fetched from the server private long totalCount; // the number of the HTTP requests private int requestNum; QueryIterator(Class<T> clz, CMSQuery query, CMSClientService service, CMSClientContext context) { if (query.isCountOnly()) { throw new CMSClientException("Please use the query instead of query iteration for count only query!"); } this.clz = clz; this.query = new CMSQuery(query); this.service = service; this.context = context; this.entities = new LinkedList<T>(); this.nextHint = query.getHint(); this.nextLimit = query.getLimits(); this.nextSkip = query.getSkips(); this.cursorString = query.getCursor(); this.hasMore = true; this.requestNum = 0; this.totalCount = 0l; } @Override public boolean hasNext() { if (entities.size() <= 0) { fetch(); } if (entities.size() > 0) { return true; } return hasMore; } /** * Iterative get next entity. */ @Override public T next() { if (hasNext() && entities.size() > 0) { return entities.remove(); } else { return null; } } /** * Returns the entities in the given page(skip,limit). * * NOTE: iterator is stateful, this page is started from the current * iterator cursor. * * @param skip * @param limit * - 0 means no limit, get all left. * @return */ public List<T> getNextPage(int skip, int limit) { Preconditions.checkArgument(skip >= 0, "skip must be >=0!"); Preconditions.checkArgument(limit >= 0, "limit must be >=0!"); while (skip > 0 && hasNext()) { skip--; next(); } if (skip > 0) { return Collections.emptyList(); } List<T> result = new LinkedList<T>(); if (limit == 0) { while (hasNext()) { result.add(next()); } } else { while (limit > 0 && hasNext()) { result.add(next()); limit--; } } return result; } /** * Returns all the <b>left</b> entities not fetched in this iterator. * * NOTE: iterator is stateful, the returned result is started from the * current iterator cursor. * * @return */ public List<T> getRemaining() { List<T> result = new LinkedList<T>(); while (hasNext()) { result.add(next()); } return result; } private void fetch() { try { int fetchedSize = 0; while (hasMore && fetchedSize <= 0) { query.setHint(nextHint); query.setSkips(nextSkip); query.setLimits(nextLimit); query.setMaxFetch(maxFetch); query.setSortOn(sortOn); query.setSortOrder(sortOrder); query.setCursor(cursorString); requestNum++; logger.debug(String.format("query iteration: %d round, parameter: %s", requestNum, query.getQueryParams())); CMSQueryResult<T> result = service.query(query, clz, context); nextHint = result.getHint(); nextSkip = result.getSkips(); nextLimit = result.getLimits(); cursorString = result.getCursor(); sortOn = result.getSortOn(); sortOrder = result.getSortOrder(); maxFetch = result.getMaxFetch(); hasMore = result.isHasMore(); fetchedSize += result.getEntities().size(); entities.addAll(result.getEntities()); totalCount += fetchedSize; logger.debug(String.format( "%s round query iteration, fetch entity number : %d, total fetched count : %d!", requestNum, fetchedSize, totalCount)); } } catch (CMSClientException ce) { String msg = "query iteration error, got CMSClientException"; logger.error(msg, ce); throw ce; } catch (Exception e) { String msg = "query iteration error, got exception"; logger.error(msg, e); throw new CMSClientException(msg, e); } } @Override public void remove() { throw new UnsupportedOperationException("Remove query entities not supported"); } public long getTotalCount() { return totalCount; } public int getRequestNum() { return requestNum; } public int getNextHint() { return nextHint; } public long[] getNextSkip() { return nextSkip; } public String getCursorString() { return cursorString; } public long[] getNextLimit() { return nextLimit; } public boolean isHasMore() { return hasMore; } }