Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / KeyRange.java
blobc8f7cf18b710937508c16ba853c307c2b1fe663e
1 // Copyright 2009 Google Inc. All Rights Reserved.
2 package com.google.appengine.api.datastore;
4 import java.io.Serializable;
5 import java.util.Iterator;
6 import java.util.NoSuchElementException;
8 /**
9 * Represents a range of unique datastore identifiers from
10 * {@code getStart().getId()} to {@code getEnd().getId()} inclusive.
11 * If an instance of this class is the result of a call to
12 * {@code DatastoreService.allocateIds()}, the {@link Key Keys} returned by
13 * this instance have been consumed in the datastore's id-space and are
14 * guaranteed never to be reused.
15 * <br>
16 * This class can be used to construct {@link Entity Entities} with {@link
17 * Key Keys} that have specific id values without fear of the datastore
18 * creating new records with those same ids at a later date. This can be
19 * helpful as part of a data migration or large bulk upload where you may need
20 * to preserve existing ids and relationships between entities.
21 * <br>
22 * This class is threadsafe but the {@link Iterator Iterators} returned by
23 * {@link #iterator()} are not.
26 public final class KeyRange implements Iterable<Key>, Serializable {
27 static final long serialVersionUID = 962890261927141064L;
29 private final Key parent;
30 private final String kind;
31 private final Key start;
32 private final Key end;
33 private final AppIdNamespace appIdNamespace;
35 public KeyRange(Key parent, String kind, long start, long end) {
36 this(parent, kind, start, end, DatastoreApiHelper.getCurrentAppIdNamespace());
39 KeyRange(Key parent, String kind, long start, long end, AppIdNamespace appIdNamespace) {
40 if (parent != null && !parent.isComplete()) {
41 throw new IllegalArgumentException("Invalid parent: not a complete key");
44 if (kind == null || kind.equals("")) {
45 throw new IllegalArgumentException("Invalid kind: cannot be null or empty");
48 if (start < 1) {
49 throw new IllegalArgumentException("Illegal start " + start + ": less than 1");
52 if (end < start) {
53 throw new IllegalArgumentException("Illegal end " + end + ": less than start " + start);
56 this.parent = parent;
57 this.kind = kind;
58 this.appIdNamespace = appIdNamespace;
59 this.start = KeyFactory.createKey(parent, kind, start, appIdNamespace);
60 this.end = KeyFactory.createKey(parent, kind, end, appIdNamespace);
63 /**
64 * This constructor exists for frameworks (e.g. Google Web Toolkit)
65 * that require it for serialization purposes. It should not be
66 * called explicitly.
68 @SuppressWarnings("unused")
69 private KeyRange() {
70 parent = null;
71 kind = null;
72 start = null;
73 end = null;
74 appIdNamespace = null;
77 AppIdNamespace getAppIdNamespace() {
78 return appIdNamespace;
81 /**
82 * @return The parent {@link Key} of the range.
84 Key getParent() {
85 return parent;
88 /**
89 * @return The kind of the range.
91 String getKind() {
92 return kind;
95 /**
96 * @return The first {@link Key} in the range.
98 public Key getStart() {
99 return start;
103 * @return The last {@link Key} in the range.
105 public Key getEnd() {
106 return end;
110 * @return The size of the range.
112 public long getSize() {
113 return end.getId() - start.getId() + 1;
116 @Override
117 public Iterator<Key> iterator() {
118 return new IdRangeIterator();
121 @Override
122 public boolean equals(Object obj) {
123 if (obj == null || !(obj instanceof KeyRange)) {
124 return false;
126 KeyRange that = (KeyRange) obj;
128 return (this.start.equals(that.start) && this.end.equals(that.end));
131 @Override
132 public int hashCode() {
133 return 31 * start.hashCode() + end.hashCode();
137 * {@link Iterator} implementation that returns {@link Key Keys}
138 * in the range defined by the enclosing {@link KeyRange}.
140 private final class IdRangeIterator implements Iterator<Key> {
141 private long next = start.getId();
143 @Override
144 public boolean hasNext() {
145 return next <= end.getId();
148 @Override
149 public Key next() {
150 if (!hasNext()) {
151 throw new NoSuchElementException();
153 return KeyFactory.createKey(parent, kind, next++, appIdNamespace);
156 @Override
157 public void remove() {
158 throw new UnsupportedOperationException();