Add ForwarderStatus and unit test
diff --git a/src/main/java/com/intel/jndn/management/NFD.java b/src/main/java/com/intel/jndn/management/NFD.java
index c0910b5..56d98ff 100644
--- a/src/main/java/com/intel/jndn/management/NFD.java
+++ b/src/main/java/com/intel/jndn/management/NFD.java
@@ -17,6 +17,7 @@
 import com.intel.jndn.management.types.ControlResponse;
 import com.intel.jndn.management.types.FaceStatus;
 import com.intel.jndn.management.types.FibEntry;
+import com.intel.jndn.management.types.ForwarderStatus;
 import com.intel.jndn.management.types.LocalControlHeader;
 import com.intel.jndn.management.types.RibEntry;
 import com.intel.jndn.utils.SimpleClient;
@@ -52,7 +53,7 @@
    * to /localhost/nfd which should always respond if the requestor is on the
    * same machine as the NDN forwarding daemon.
    *
-   * @param face
+   * @param face only a localhost Face
    * @return true if successful, false otherwise
    */
   public static boolean pingLocal(Face face) {
@@ -84,12 +85,29 @@
   }
 
   /**
+   * Retrieve the status of the given forwarder; calls /localhost/nfd/status
+   * which requires a local Face (all non-local packets are dropped)
+   *
+   * @param forwarder only a localhost Face
+   * @return the forwarder status object, see
+   * http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus.
+   * @throws java.lang.Exception
+   */
+  public static ForwarderStatus getForwarderStatus(Face forwarder) throws Exception {
+    Data data = retrieveDataSet(forwarder, new Name("/localhost/nfd/status"));
+    ForwarderStatus status = new ForwarderStatus();
+    status.wireDecode(data.getContent().buf());
+    return status;
+  }
+
+  /**
    * Retrieve a list of faces and their status from the given forwarder; calls
    * /localhost/nfd/faces/list which requires a local Face (all non-local
    * packets are dropped)
    *
-   * @param forwarder Only a localhost Face
-   * @return
+   * @param forwarder only a localhost Face
+   * @return a list of face status objects, see
+   * http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt.
    * @throws java.lang.Exception
    */
   public static List<FaceStatus> getFaceList(Face forwarder) throws Exception {
@@ -102,8 +120,9 @@
    * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
    * non-local packets are dropped).
    *
-   * @param forwarder Only a localhost Face
-   * @return
+   * @param forwarder only a localhost Face
+   * @return a list of FIB entries, see
+   * http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset.
    * @throws java.lang.Exception
    */
   public static List<FibEntry> getFibList(Face forwarder) throws Exception {
@@ -116,8 +135,9 @@
    * /localhost/nfd/rib/list which requires a local Face (all non-local packets
    * are dropped).
    *
-   * @param forwarder Only a localhost Face
-   * @return
+   * @param forwarder only a localhost Face
+   * @return a list of RIB entries, i.e. routes, see
+   * http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset.
    * @throws java.lang.Exception
    */
   public static List<RibEntry> getRouteList(Face forwarder) throws Exception {
@@ -130,7 +150,7 @@
    * http://named-data.net/doc/NFD/current/manpages/nfdc.html, this is more for
    * debugging; use 'register' instead
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param faceId
    * @param prefix
    * @throws java.lang.Exception
@@ -152,7 +172,7 @@
    * the local machine (management requests are to /localhost/...) and that
    * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param uri
    * @return
    * @throws java.lang.Exception
@@ -175,7 +195,7 @@
    * local machine (management requests are to /localhost/...) and that command
    * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param faceId
    * @throws java.lang.Exception
    */
@@ -235,7 +255,7 @@
    * (management requests are to /localhost/...) and that command signing has
    * been set up (e.g. forwarder.setCommandSigningInfo()).
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param controlParameters
    * @throws Exception
    */
@@ -253,7 +273,7 @@
    * forwarder to the given URI/route pair. See register(Face,
    * ControlParameters) for more details documentation.
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param uri
    * @param cost
    * @param route
@@ -272,7 +292,7 @@
    * is provided a faceId. See register(Face, ControlParameters) for full
    * documentation
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param faceId
    * @param route
    * @param cost
@@ -396,7 +416,7 @@
    * machine (management requests are to /localhost/...) and that command
    * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
    *
-   * @param forwarder Only a localhost Face
+   * @param forwarder only a localhost Face
    * @param prefix
    * @param strategy
    * @throws Exception
@@ -438,7 +458,7 @@
     if (data.getContent().buf().get(0) == ControlResponse.TLV_CONTROL_RESPONSE) {
       throw ManagementException.fromResponse(data.getContent());
     }
-    
+
     return data;
   }
 
@@ -449,7 +469,7 @@
    * (management requests are to /localhost/...) and that command signing has
    * been set up (e.g. forwarder.setCommandSigningInfo()).
    *
-   * @param forwarder Only a localhost Face, command signing info must be set
+   * @param forwarder only a localhost Face, command signing info must be set
    * @param interest As described at
    * http://redmine.named-data.net/projects/nfd/wiki/ControlCommand, the
    * requested interest must have encoded ControlParameters appended to the
diff --git a/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java b/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java
new file mode 100644
index 0000000..88ecc35
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java
@@ -0,0 +1,216 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 3, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
+ * more details.
+ */
+package com.intel.jndn.management.types;
+
+import java.nio.ByteBuffer;
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.encoding.tlv.TlvDecoder;
+import net.named_data.jndn.encoding.tlv.TlvEncoder;
+import net.named_data.jndn.util.Blob;
+
+/**
+ * Represent a ForwarderStatus object from
+ * http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus.
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class ForwarderStatus implements Decodable {
+
+  public static final int TLV_NFD_VERSION = 0x80;
+  public static final int TLV_START_TIMESTAMP = 0x81;
+  public static final int TLV_CURRENT_TIMESTAMP = 0x82;
+  public static final int TLV_NUM_NAME_TREE_ENTRIES = 0x83;
+  public static final int TLV_NUM_FIB_ENTRIES = 0x84;
+  public static final int TLV_NUM_PIT_ENTRIES = 0x85;
+  public static final int TLV_NUM_MEASUREMENT_ENTRIES = 0x86;
+  public static final int TLV_NUM_CS_ENTRIES = 0x87;
+  public static final int TLV_NUM_IN_INTERESTS = 0x90;
+  public static final int TLV_NUM_IN_DATAS = 0x91;
+  public static final int TLV_NUM_OUT_INTERESTS = 0x92;
+  public static final int TLV_NUM_OUT_DATAS = 0x93;
+
+  /**
+   * Encode using a new TLV encoder.
+   *
+   * @return The encoded buffer.
+   */
+  public final Blob wireEncode() {
+    TlvEncoder encoder = new TlvEncoder();
+    wireEncode(encoder);
+    return new Blob(encoder.getOutput(), false);
+  }
+
+  /**
+   * Encode as part of an existing encode context.
+   *
+   * @param encoder
+   */
+  public final void wireEncode(TlvEncoder encoder) {
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_OUT_DATAS, numOutDatas);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_OUT_INTERESTS, numOutInterests);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_IN_DATAS, numInDatas);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_IN_INTERESTS, numInInterests);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_CS_ENTRIES, numCsEntries);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_MEASUREMENT_ENTRIES, numMeasurementEntries);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_PIT_ENTRIES, numPitEntries);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_FIB_ENTRIES, numFibEntries);
+    encoder.writeNonNegativeIntegerTlv(TLV_NUM_NAME_TREE_ENTRIES, numNameTreeEntries);
+    encoder.writeNonNegativeIntegerTlv(TLV_CURRENT_TIMESTAMP, currentTimestamp);
+    encoder.writeNonNegativeIntegerTlv(TLV_START_TIMESTAMP, startTimestamp);
+    encoder.writeBlobTlv(TLV_NFD_VERSION, new Blob(nfdVersion).buf());
+  }
+
+  /**
+   * Decode the input from its TLV format.
+   *
+   * @param input The input buffer to decode. This reads from position() to
+   * limit(), but does not change the position.
+   * @throws EncodingException For invalid encoding.
+   */
+  public final void wireDecode(ByteBuffer input) throws EncodingException {
+    TlvDecoder decoder = new TlvDecoder(input);
+    wireDecode(decoder);
+  }
+
+  /**
+   * Decode as part of an existing decode context.
+   *
+   * @param decoder
+   * @throws EncodingException
+   */
+  @Override
+  public void wireDecode(TlvDecoder decoder) throws EncodingException {
+    this.nfdVersion = new Blob(decoder.readBlobTlv(TLV_NFD_VERSION), true).toString();
+    this.startTimestamp = decoder.readNonNegativeIntegerTlv(TLV_START_TIMESTAMP);
+    this.currentTimestamp = decoder.readNonNegativeIntegerTlv(TLV_CURRENT_TIMESTAMP);
+    this.numNameTreeEntries = decoder.readNonNegativeIntegerTlv(TLV_NUM_NAME_TREE_ENTRIES);
+    this.numFibEntries = decoder.readNonNegativeIntegerTlv(TLV_NUM_FIB_ENTRIES);
+    this.numPitEntries = decoder.readNonNegativeIntegerTlv(TLV_NUM_PIT_ENTRIES);
+    this.numMeasurementEntries = decoder.readNonNegativeIntegerTlv(TLV_NUM_MEASUREMENT_ENTRIES);
+    this.numCsEntries = decoder.readNonNegativeIntegerTlv(TLV_NUM_CS_ENTRIES);
+    this.numInInterests = decoder.readNonNegativeIntegerTlv(TLV_NUM_IN_INTERESTS);
+    this.numInDatas = decoder.readNonNegativeIntegerTlv(TLV_NUM_IN_DATAS);
+    this.numOutInterests = decoder.readNonNegativeIntegerTlv(TLV_NUM_OUT_INTERESTS);
+    this.numOutDatas = decoder.readNonNegativeIntegerTlv(TLV_NUM_OUT_DATAS);
+  }
+
+  public String getNfdVersion() {
+    return nfdVersion;
+  }
+
+  public void setNfdVersion(String nfdVersion) {
+    this.nfdVersion = nfdVersion;
+  }
+
+  public long getStartTimestamp() {
+    return startTimestamp;
+  }
+
+  public void setStartTimestamp(long startTimestamp) {
+    this.startTimestamp = startTimestamp;
+  }
+
+  public long getCurrentTimestamp() {
+    return currentTimestamp;
+  }
+
+  public void setCurrentTimestamp(long currentTimestamp) {
+    this.currentTimestamp = currentTimestamp;
+  }
+
+  public long getNumNameTreeEntries() {
+    return numNameTreeEntries;
+  }
+
+  public void setNumNameTreeEntries(long numNameTreeEntries) {
+    this.numNameTreeEntries = numNameTreeEntries;
+  }
+
+  public long getNumFibEntries() {
+    return numFibEntries;
+  }
+
+  public void setNumFibEntries(long numFibEntries) {
+    this.numFibEntries = numFibEntries;
+  }
+
+  public long getNumPitEntries() {
+    return numPitEntries;
+  }
+
+  public void setNumPitEntries(long numPitEntries) {
+    this.numPitEntries = numPitEntries;
+  }
+
+  public long getNumMeasurementEntries() {
+    return numMeasurementEntries;
+  }
+
+  public void setNumMeasurementEntries(long numMeasurementEntries) {
+    this.numMeasurementEntries = numMeasurementEntries;
+  }
+
+  public long getNumCsEntries() {
+    return numCsEntries;
+  }
+
+  public void setNumCsEntries(long numCsEntries) {
+    this.numCsEntries = numCsEntries;
+  }
+
+  public long getNumInInterests() {
+    return numInInterests;
+  }
+
+  public void setNumInInterests(long numInInterests) {
+    this.numInInterests = numInInterests;
+  }
+
+  public long getNumInDatas() {
+    return numInDatas;
+  }
+
+  public void setNumInDatas(long numInDatas) {
+    this.numInDatas = numInDatas;
+  }
+
+  public long getNumOutInterests() {
+    return numOutInterests;
+  }
+
+  public void setNumOutInterests(long numOutInterests) {
+    this.numOutInterests = numOutInterests;
+  }
+
+  public long getNumOutDatas() {
+    return numOutDatas;
+  }
+
+  public void setNumOutDatas(long numOutDatas) {
+    this.numOutDatas = numOutDatas;
+  }
+
+  private String nfdVersion = "";
+  private long startTimestamp;
+  private long currentTimestamp;
+  private long numNameTreeEntries;
+  private long numFibEntries;
+  private long numPitEntries;
+  private long numMeasurementEntries;
+  private long numCsEntries;
+  private long numInInterests;
+  private long numInDatas;
+  private long numOutInterests;
+  private long numOutDatas;
+}