// Copyright 2011 Google Inc. All Rights Reserved. package com.google.appengine.tools.mapreduce.inputs; import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService; import static com.google.appengine.api.datastore.Entity.KEY_RESERVED_PROPERTY; import static com.google.appengine.api.datastore.FetchOptions.Builder.withChunkSize; import static com.google.appengine.api.datastore.Query.FilterOperator.GREATER_THAN; import static com.google.appengine.api.datastore.Query.FilterOperator.GREATER_THAN_OR_EQUAL; import static com.google.appengine.api.datastore.Query.FilterOperator.LESS_THAN; import com.google.appengine.api.datastore.Entity; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.Query; import com.google.appengine.api.datastore.QueryResultIterator; import com.google.appengine.tools.mapreduce.InputReader; import com.google.common.base.Preconditions; /** */ class DatastoreInputReader extends InputReader<Key, Entity> { // --------------------------- STATIC FIELDS --------------------------- private static final long serialVersionUID = -2164845668646485549L; // ------------------------------ FIELDS ------------------------------ private final String entityKind; private final Key startKey; private final Key endKey; private final int batchSize = 50; private Key currentKey; private transient Entity currentValue = null; private transient QueryResultIterator<Entity> iterator; // --------------------------- CONSTRUCTORS --------------------------- DatastoreInputReader(String entityKind, Key startKey, Key endKey) { this.entityKind = entityKind; this.startKey = startKey; this.endKey = endKey; } // ------------------------ INTERFACE METHODS ------------------------ // --------------------- Interface Iterator --------------------- @Override public boolean hasNext() { if (iterator == null) { createIterator(); } if (!iterator.hasNext()) { return false; } Entity entity = iterator.next(); currentKey = entity.getKey(); currentValue = entity; return true; } @Override public KeyValue<Key, Entity> next() { return KeyValue.of(currentKey, currentValue); } // ------------------------ IMPLEMENTING METHODS ------------------------ @Override public double getProgress() { return 0.0; } // --------------------- GETTER / SETTER METHODS --------------------- Key getEndKey() { return endKey; } Key getStartKey() { return startKey; } // -------------------------- INSTANCE METHODS -------------------------- private void createIterator() { Preconditions.checkState(iterator == null); Query q = new Query(entityKind); if (currentKey == null) { if (startKey != null) { q.addFilter(KEY_RESERVED_PROPERTY, GREATER_THAN_OR_EQUAL, startKey); } } else { q.addFilter(KEY_RESERVED_PROPERTY, GREATER_THAN, currentKey); } if (endKey != null) { q.addFilter(KEY_RESERVED_PROPERTY, LESS_THAN, endKey); } q.addSort(KEY_RESERVED_PROPERTY); iterator = getDatastoreService().prepare(q).asQueryResultIterator(withChunkSize(batchSize)); } }