/*
* Copyright (c) 2014 Red Hat, Inc. and/or its affiliates.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cheng Fang - Initial API and implementation
*/
package org.jberet.support.io;
import java.io.Serializable;
import javax.batch.api.BatchProperty;
import javax.batch.api.chunk.ItemReader;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.inject.Named;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
/**
* An implementation of {@code javax.batch.api.chunk.ItemReader} that reads from a collection in a MongoDB database.
*
* @see MongoItemWriter
* @see MongoItemReaderWriterBase
* @since 1.0.2
*/
@Named
@Dependent
public class MongoItemReader extends MongoItemReaderWriterBase implements ItemReader {
/**
* Query criteria or conditions, which identify the documents that MongoDB returns to the client.
* Its value is a JSON string. Optional property and defaults to null. For example,
* <pre>
* { age: { $gt: 18 } }
* </pre>
*/
@Inject
@BatchProperty
protected String criteria;
/**
* Specifies the fields from the matching documents to return. Its value is a JSON string. Optional property and
* defaults to null. For example,
* <pre>
* { name: 1, address: 1}
* </pre>
*/
@Inject
@BatchProperty
protected String projection;
/**
* Modifies the query to limit the number of matching documents to return to the client. Optional property and
* defaults to null (limit is not set).
*/
@Inject
@BatchProperty
protected int limit;
/**
* Limits the number of elements returned in one batch. A cursor typically fetches a batch of result objects and
* store them locally. If batchSize is positive, it represents the size of each batch of objects retrieved.
* It can be adjusted to optimize performance and limit data transfer. If batchSize is negative,
* it will limit of number objects returned, that fit within the max batch size limit (usually 4MB),
* and cursor will be closed. For example if batchSize is -10, then the server will return a maximum of 10
* documents and as many as can fit in 4MB, then close the cursor.
* <p>
* Note that this feature is different from limit() in that documents must fit within a maximum size,
* and it removes the need to send a request to close the cursor server-side. The batch size can be changed
* even after a cursor is iterated, in which case the setting will apply on the next batch retrieval.
*
* @see "com.mongodb.DBCursor#batchSize(int)"
*/
@Inject
@BatchProperty
protected int batchSize;
/**
* Specifies how to sort the cursor's elements. Optional property and defaults to null. Its value is a JSON string,
* for example,
* <pre>
* { age: 1 }
* </pre>
* @see "com.mongodb.DBCursor#sort(com.mongodb.DBObject)"
*/
@Inject
@BatchProperty
protected String sort;
/**
* Specifies the number of elements to discard at the beginning of the cursor. Optional property and defaults to 0
* (do not discard any elements).
*
* @see "com.mongodb.DBCursor#skip(int)"
*/
@Inject
@BatchProperty
protected int skip;
protected org.mongojack.DBCursor<Object> cursor;
@Override
public void open(final Serializable checkpoint) throws Exception {
super.init();
final DBObject query = criteria == null ? new BasicDBObject() : (DBObject) JSON.parse(criteria);
cursor = projection == null ? jacksonCollection.find(query) : jacksonCollection.find(query, (DBObject) JSON.parse(projection));
if (limit != 0) {
cursor.limit(limit);
}
if (sort != null) {
cursor.sort((DBObject) JSON.parse(sort));
}
if (checkpoint != null) {
cursor.skip((Integer) checkpoint);
} else if (skip > 0) {
cursor.skip(skip);
}
if (batchSize != 0) {
cursor.batchSize(batchSize);
}
}
@Override
public Object readItem() throws Exception {
if (cursor.hasNext()) {
final Object readValue = cursor.next();
if (!skipBeanValidation) {
ItemReaderWriterBase.validate(readValue);
}
return readValue;
}
return null;
}
@Override
public void close() throws Exception {
if (cursor != null) {
cursor.close();
cursor = null;
}
}
@Override
public Serializable checkpointInfo() throws Exception {
return cursor.numSeen() - 1;
}
}