/src/com/google/appengine/datanucleus/query/AbstractIterator.java

http://datanucleus-appengine.googlecode.com/ · Java · 153 lines · 50 code · 13 blank · 90 comment · 6 complexity · 3945570889f78cbd7e64489073e2096e MD5 · raw file

  1. /*
  2. * Copyright (C) 2007 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.google.appengine.datanucleus.query;
  17. import java.util.Iterator;
  18. import java.util.NoSuchElementException;
  19. /**
  20. * This class provides a skeletal implementation of the {@code Iterator}
  21. * interface, to make this interface easier to implement for certain types of
  22. * data sources.
  23. *
  24. * <p>{@code Iterator} requires its implementations to support querying the
  25. * end-of-data status without changing the iterator's state, using the {@link
  26. * #hasNext} method. But many data sources, such as {@link
  27. * java.io.Reader#read()}), do not expose this information; the only way to
  28. * discover whether there is any data left is by trying to retrieve it. These
  29. * types of data sources are ordinarily difficult to write iterators for. But
  30. * using this class, one must implement only the {@link #computeNext} method,
  31. * and invoke the {@link #endOfData} method when appropriate.
  32. *
  33. * <p>Another example is an iterator that skips over null elements in a backing
  34. * iterator. This could be implemented as: <pre> {@code
  35. *
  36. * public static Iterator<String> skipNulls(final Iterator<String> in) {
  37. * return new AbstractIterator<String>() {
  38. * protected String computeNext() {
  39. * while (in.hasNext()) {
  40. * String s = in.next();
  41. * if (s != null) {
  42. * return s;
  43. * }
  44. * }
  45. * return endOfData();
  46. * }
  47. * };
  48. * }}</pre>
  49. *
  50. * This class supports iterators that include null elements. The {@link
  51. * #remove()} method throws an {@link UnsupportedOperationException}, but
  52. * this can be overridden to support removal.
  53. *
  54. * @author Kevin Bourrillion
  55. */
  56. abstract class AbstractIterator<T> implements Iterator<T> {
  57. private State state = State.NOT_READY;
  58. private enum State {
  59. /** We have computed the next element and haven't returned it yet. */
  60. READY,
  61. /** We haven't yet computed or have already returned the element. */
  62. NOT_READY,
  63. /** We have reached the end of the data and are finished. */
  64. DONE,
  65. /** We've suffered an exception and are kaput. */
  66. FAILED,
  67. }
  68. private T next;
  69. /**
  70. * Returns the next element. <b>Note:</b> the implementation must call {@link
  71. * #endOfData} when there are no elements left in the iteration. Failure to do
  72. * so could result in an infinite loop.
  73. *
  74. * <p>The initial invocation of {@link #hasNext()} or {@link #next()} calls
  75. * this method, as does the first invocation of {@code hasNext} or
  76. * {@code next} following each successful call to {@code next}. Once the
  77. * implementation either invokes {@code endOfData} or throws an exception,
  78. * {@code computeNext} is guaranteed to never be called again.
  79. *
  80. * <p>If this method throws an exception, it will propagate outward to the
  81. * {@code hasNext()} or {@code next()} invocation that invoked this method.
  82. * Any further attempts to use the iterator will result in an {@link
  83. * IllegalStateException}.
  84. *
  85. * @return the next element if there was one. If {@code endOfData} was called
  86. * during execution, the return value will be ignored.
  87. * @throws RuntimeException if any unrecoverable error happens. This exception
  88. * will propagate outward to the {@code hasNext()}, {@code next()}, or
  89. * {@code peek()} invocation that invoked this method. Any further
  90. * attempts to use the iterator will result in an
  91. * {@link IllegalStateException}.
  92. */
  93. protected abstract T computeNext();
  94. /**
  95. * Implementations of {@code computeNext} <b>must</b> invoke this method when
  96. * there are no elements left in the iteration.
  97. *
  98. * @return {@code null}; a convenience so your {@link #computeNext}
  99. * implementation can use the simple statement {@code return endOfData();}
  100. */
  101. protected final T endOfData() {
  102. state = State.DONE;
  103. return null;
  104. }
  105. public boolean hasNext() {
  106. if (state == State.FAILED) {
  107. throw new IllegalStateException();
  108. }
  109. switch (state) {
  110. case DONE:
  111. return false;
  112. case READY:
  113. return true;
  114. default:
  115. }
  116. return tryToComputeNext();
  117. }
  118. private boolean tryToComputeNext() {
  119. state = State.FAILED; // temporary pessimism
  120. next = computeNext();
  121. if (state != State.DONE) {
  122. state = State.READY;
  123. return true;
  124. }
  125. return false;
  126. }
  127. public T next() {
  128. if (!hasNext()) {
  129. throw new NoSuchElementException();
  130. }
  131. state = State.NOT_READY;
  132. return next;
  133. }
  134. /**
  135. * This method is not supported.
  136. */
  137. public void remove() {
  138. throw new UnsupportedOperationException();
  139. }
  140. }