/src/main/java/com/velix/jmongo/CursorIterator.java
https://github.com/velna/jmongo · Java · 218 lines · 182 code · 17 blank · 19 comment · 46 complexity · 43a3829fb73ed51a11d43b038cc8d07e MD5 · raw file
- /**
- * JMongo is a mongodb driver writtern in java.
- * Copyright (C) 2010 Xiaohu Huang
- *
- * JMongo is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * JMongo is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with JMongo. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.velix.jmongo;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
- import java.util.NoSuchElementException;
- import org.apache.log4j.Logger;
- import com.velix.bson.BSONDocument;
- import com.velix.jmongo.protocol.GetMoreMessage;
- import com.velix.jmongo.protocol.KillCursorsMessage;
- import com.velix.jmongo.protocol.QueryMessage;
- import com.velix.jmongo.protocol.ReplyMessage;
- public class CursorIterator<T extends BSONDocument> implements Iterator<T> {
- private final static Logger LOG = Logger.getLogger(CursorIterator.class);
- private Boolean hasNext = null;
- private ReplyMessage<T> replyMessage;
- private QueryMessage queryMessage;
- private Iterator<T> resultIterator;
- private ConnectionPool pool;
- private boolean getMore = false;
- private boolean closed = false;
- private Cursor<T> cursor;
- private int numberReturned;
- private int numberToReturn;
- public CursorIterator(ConnectionPool pool, Cursor<T> cursor) {
- this.pool = pool;
- this.cursor = cursor;
- prepareQueryMessage();
- }
- private void prepareQueryMessage() {
- // cal numberToReturn
- numberToReturn = cursor.getLimit();
- if (cursor.getBatchSize() > 0) {
- if (numberToReturn == 0) {
- numberToReturn = cursor.getBatchSize();
- } else {
- numberToReturn = Math
- .min(numberToReturn, cursor.getBatchSize());
- }
- }
- // prepare queryMessage
- queryMessage = new QueryMessage();
- queryMessage
- .setFullCollectionName(cursor.getCollection().getFullName());
- queryMessage.setNumberToReturn(numberToReturn);
- queryMessage.setNumberToSkip(cursor.getSkip());
- if (cursor.isExplain() || cursor.isSnapshot()
- || (null != cursor.getSort() && !cursor.getSort().isEmpty())
- || null != cursor.getHint()) {
- BSONDocument query = new MongoDocument();
- query.put("query", cursor.getQuery());
- if (null != cursor.getSort() && !cursor.getSort().isEmpty()) {
- query.put("orderby", cursor.getSort());
- }
- if (cursor.isExplain()) {
- query.put("$explain", true);
- }
- if (cursor.isSnapshot()) {
- query.put("$snapshot", true);
- }
- if (null != cursor.getHint()) {
- query.put("$hint", cursor.getHint());
- }
- queryMessage.setQuery(query);
- } else {
- queryMessage.setQuery(cursor.getQuery());
- }
- queryMessage.setReturnFieldSelector(cursor.getFields());
- queryMessage.setTailable(cursor.isTailableCursor());
- queryMessage.setNoCursorTimeout(cursor.isNoCursorTimeout());
- queryMessage.setSlaveOk(cursor.isSlaveOk());
- queryMessage.setAwaitData(cursor.isAwaitData());
- }
- @SuppressWarnings("unchecked")
- @Override
- public boolean hasNext() throws IllegalStateException {
- if (closed) {
- return false;
- }
- if (Boolean.FALSE == hasNext) {
- return false;
- }
- if (cursor.getLimit() > 0 && cursor.getLimit() <= this.numberReturned) {
- return false;
- }
- if (null != resultIterator) {
- if (resultIterator.hasNext()) {
- hasNext = Boolean.TRUE;
- } else if (replyMessage.getCursorID() == 0) {
- hasNext = Boolean.FALSE;
- }
- } else {
- try {
- Connection connection = getConnection();
- try {
- if (getMore) {
- GetMoreMessage getMoreMessage = new GetMoreMessage();
- getMoreMessage.setFullCollectionName(cursor
- .getCollection().getFullName());
- getMoreMessage.setNumberToReturn(numberToReturn);
- getMoreMessage.setCursorID(replyMessage.getCursorID());
- connection.send(getMoreMessage);
- } else {
- connection.send(queryMessage);
- getMore = true;
- }
- replyMessage = (ReplyMessage<T>) connection.receive(cursor
- .getCollection().getObjectClass());
- if (null != replyMessage) {
- resultIterator = replyMessage.getDocuments().iterator();
- } else {
- resultIterator = null;
- }
- if (null != resultIterator) {
- hasNext = resultIterator.hasNext();
- } else {
- hasNext = Boolean.FALSE;
- }
- } finally {
- connection.close();
- }
- } catch (IOException e) {
- throw new MongoException(e);
- }
- }
- return hasNext;
- }
- @Override
- public T next() throws IllegalStateException {
- check();
- if (hasNext()) {
- numberReturned++;
- T ret = resultIterator.next();
- if (ret instanceof MongoCollectionAware) {
- ((MongoCollectionAware) ret).setMongoCollection(cursor
- .getCollection());
- }
- return ret;
- }
- throw new NoSuchElementException("no more documents");
- }
- @Override
- public void remove() throws UnsupportedOperationException {
- throw new UnsupportedOperationException("remove() is not supported yet");
- }
- public void close() throws IOException {
- closed = true;
- killCursor();
- }
- private void killCursor() throws IOException {
- if (null != replyMessage && replyMessage.getCursorID() != 0) {
- Connection connection = getConnection();
- try {
- KillCursorsMessage message = new KillCursorsMessage();
- message.setNumberOfCursorIDs(1);
- List<Long> cursorIdList = new ArrayList<Long>(1);
- cursorIdList.add(replyMessage.getCursorID());
- message.setCursorIDs(cursorIdList);
- connection.send(message);
- } finally {
- connection.close();
- }
- }
- }
- private Connection getConnection() throws IOException {
- Connection connection = pool.getConnection();
- this.cursor.getCollection().getDB().authenticate(connection);
- return connection;
- }
- private void check() {
- if (closed) {
- throw new IllegalStateException("cursor is already closed");
- }
- }
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- try {
- killCursor();
- } catch (Throwable e) {
- LOG.error("error when kill cursors: ", e);
- }
- }
- }