Switch to FutureData; add SegmentedClient
diff --git a/src/main/java/com/intel/jndn/utils/FutureData.java b/src/main/java/com/intel/jndn/utils/FutureData.java
new file mode 100644
index 0000000..5c881ee
--- /dev/null
+++ b/src/main/java/com/intel/jndn/utils/FutureData.java
@@ -0,0 +1,183 @@
+/*
+ * File name: FuturePacket.java
+ * 
+ * Purpose: Reference to a Packet that has yet to be returned from the network.
+ * 
+ * © Copyright Intel Corporation. All rights reserved.
+ * Intel Corporation, 2200 Mission College Boulevard,
+ * Santa Clara, CA 95052-8119, USA
+ */
+package com.intel.jndn.utils;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.Name;
+import net.named_data.jndn.encoding.EncodingException;
+
+/**
+ * Reference to a Packet that has yet to be returned from the network; see use
+ * in WindowBuffer.java. Usage:
+ * <pre><code>
+ * FuturePacket futurePacket = new FuturePacket(face);
+ * face.expressInterest(interest, new OnData(){
+ *	... futurePacket.resolve(data); ...
+ * }, new OnTimeout(){
+ *  ... futurePacket.reject(new TimeoutException());
+ * });
+ * Packet resolvedPacket = futurePacket.get(); // will block and call face.processEvents() until complete
+ * </code></pre>
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class FutureData implements Future<Data> {
+
+  private final Face face;
+  private final Name name;
+  private Data data;
+  private boolean cancelled = false;
+  private Throwable error;
+
+  /**
+   * Constructor
+   *
+   * @param face
+   * @param name
+   */
+  public FutureData(Face face, Name name) {
+    this.face = face;
+    this.name = new Name(name);
+  }
+
+  /**
+   * Get the packet interest name
+   *
+   * @return
+   */
+  public Name getName() {
+    return name;
+  }
+
+  /**
+   * Cancel the current request.
+   *
+   * @param mayInterruptIfRunning
+   * @return
+   */
+  @Override
+  public boolean cancel(boolean mayInterruptIfRunning) {
+    cancelled = true;
+    return cancelled;
+  }
+
+  /**
+   * Determine if this request is cancelled.
+   *
+   * @return
+   */
+  @Override
+  public boolean isCancelled() {
+    return cancelled;
+  }
+
+  /**
+   * Determine if the request has completed (successfully or not).
+   *
+   * @return
+   */
+  @Override
+  public boolean isDone() {
+    return data != null || error != null;
+  }
+
+  /**
+   * Set the packet when successfully retrieved; unblocks get().
+   *
+   * @param d
+   */
+  public void resolve(Data d) {
+    data = d;
+  }
+
+  /**
+   * Set the exception when request failed; unblocks get().
+   *
+   * @param e
+   */
+  public void reject(Throwable e) {
+    error = e;
+  }
+
+  /**
+   * Block until packet is retrieved.
+   *
+   * @return
+   * @throws InterruptedException
+   * @throws ExecutionException
+   */
+  @Override
+  public Data get() throws InterruptedException, ExecutionException {
+    while (!isDone() && !isCancelled()) {
+      try {
+        synchronized (face) {
+          face.processEvents();
+        }
+      } catch (EncodingException | IOException e) {
+        throw new ExecutionException("Failed to retrieve packet.", e);
+      }
+    }
+    // case: cancelled
+    if (cancelled) {
+      throw new InterruptedException("Interrupted by user.");
+    }
+    // case: error
+    if (error != null) {
+      throw new ExecutionException("Future rejected with error.", error);
+    }
+    // case: packet
+    return data;
+  }
+
+  /**
+   * Block until packet is retrieved or timeout is reached.
+   *
+   * @param timeout
+   * @param unit
+   * @return
+   * @throws InterruptedException
+   * @throws ExecutionException
+   * @throws TimeoutException
+   */
+  @Override
+  public Data get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+    long interval = TimeUnit.MILLISECONDS.convert(timeout, unit);
+    long endTime = System.currentTimeMillis() + interval;
+    while (!isDone() && !isCancelled() && System.currentTimeMillis() < endTime) {
+      try {
+        synchronized (face) {
+          face.processEvents();
+        }
+      } catch (EncodingException | IOException e) {
+        throw new ExecutionException("Failed to retrieve packet.", e);
+      }
+    }
+    // case: timed out
+    if (System.currentTimeMillis() < endTime) {
+      throw new TimeoutException("Timed out");
+    }
+    // case: cancelled
+    if (cancelled) {
+      throw new InterruptedException("Interrupted by user.");
+    }
+    // case: error
+    if (error != null) {
+      throw new ExecutionException("Future rejected.", error);
+    }
+    // case: packet
+    return data;
+  }
+}