Major refactoring and improvements

This commit removes dependency on jndn-utils (it requires Java 8, while
jndn-management needs to be compatible with Java 7 to support Android)

Some changes include interface unification with structures in ndn-cxx library

Change-Id: I944ea41e225edc1848657ed574b625c7ec18df5d
diff --git a/src/main/java/com/intel/jndn/management/ManagementException.java b/src/main/java/com/intel/jndn/management/ManagementException.java
index 70a15d1..69e209a 100644
--- a/src/main/java/com/intel/jndn/management/ManagementException.java
+++ b/src/main/java/com/intel/jndn/management/ManagementException.java
@@ -11,11 +11,10 @@
  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  * more details.
  */
+
 package com.intel.jndn.management;
 
 import com.intel.jndn.management.types.ControlResponse;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.util.Blob;
 
 /**
  * Represent a failure to correctly manage the NDN Forwarding Daemon (NFD).
@@ -25,19 +24,15 @@
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class ManagementException extends Exception {
-
   /**
-   *
-   * @param message
+   * Constructor from the message
    */
   public ManagementException(String message) {
     super(message);
   }
 
   /**
-   *
-   * @param message
-   * @param cause
+   * Constructor from the message and the cause
    */
   public ManagementException(String message, Throwable cause) {
     super(message, cause);
@@ -45,26 +40,6 @@
 
   /**
    * Parse an NFD response to create a ManagementException.
-   *
-   * @param forwarderResponse
-   * @return
-   */
-  public static ManagementException fromResponse(Blob forwarderResponse) {
-    ControlResponse response = new ControlResponse();
-    try {
-      response.wireDecode(forwarderResponse.buf());
-      String message = "Action failed, forwarder returned: " + response.getStatusCode() + " " + response.getStatusText();
-      return new ManagementException(message);
-    } catch (EncodingException e) {
-      return new ManagementException("Action failed and forwarder response was unparseable.", e);
-    }
-  }
-
-  /**
-   * Parse an NFD response to create a ManagementException.
-   *
-   * @param forwarderResponse
-   * @return
    */
   public static ManagementException fromResponse(ControlResponse response) {
     String message = "Action failed, forwarder returned: " + response.getStatusCode() + " " + response.getStatusText();
diff --git a/src/main/java/com/intel/jndn/management/NFD.java b/src/main/java/com/intel/jndn/management/NFD.java
deleted file mode 100644
index 9eb9180..0000000
--- a/src/main/java/com/intel/jndn/management/NFD.java
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * 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;
-
-import com.intel.jndn.management.types.StatusDataset;
-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.management.types.StrategyChoice;
-import com.intel.jndn.utils.client.impl.AdvancedClient;
-import com.intel.jndn.utils.client.impl.SimpleClient;
-import java.io.IOException;
-import java.util.List;
-import net.named_data.jndn.ControlParameters;
-import net.named_data.jndn.Data;
-import net.named_data.jndn.Face;
-import net.named_data.jndn.ForwardingFlags;
-import net.named_data.jndn.Interest;
-import net.named_data.jndn.Name;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.security.SecurityException;
-import java.util.logging.Logger;
-import net.named_data.jndn.KeyLocator;
-
-/**
- * Helper class for interacting with an NDN forwarder daemon; see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/Management">http://redmine.named-data.net/projects/nfd/wiki/Management</a>
- * for explanations of the various protocols used.
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class NFD {
-
-  public final static long DEFAULT_TIMEOUT = 2000;
-  public final static int OK_STATUS = 200;
-  static private final Logger logger = Logger.getLogger(NFD.class.getName());
-
-  /**
-   * Ping a forwarder on an existing face to verify that the forwarder is
-   * working and responding to requests; this version sends a discovery packet
-   * to /localhost/nfd which should always respond if the requestor is on the
-   * same machine as the NDN forwarding daemon.
-   *
-   * @param face only a localhost Face
-   * @return true if successful, false otherwise
-   */
-  public static boolean pingLocal(Face face) {
-    return ping(face, new Name("/localhost/nfd"));
-  }
-
-  /**
-   * Request a name on an existing face to verify the forwarder is working and
-   * responding to requests. Note that the name must be served or cached on the
-   * forwarder for this to return true.
-   *
-   * @param face a {@link Face} to ping
-   * @param name a known {@link Name} that the remote node will answer to
-   * @return true if successful, false otherwise
-   */
-  public static boolean ping(Face face, Name name) {
-    // build interest
-    Interest interest = new Interest(name);
-    interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
-    interest.setMustBeFresh(true);
-
-    // send packet
-    try {
-      Data data = SimpleClient.getDefault().getSync(face, interest);
-      return data != null;
-    } catch (IOException e) {
-      return false;
-    }
-  }
-
-  /**
-   * 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
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus">
-   * http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus</a>.
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the returned status could not be decoded
-   */
-  public static ForwarderStatus getForwarderStatus(Face forwarder) throws IOException, EncodingException {
-    Data data = retrieveStatus(forwarder);
-    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 a list of face status objects, see
-   * http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt.
-   * @throws IOException if the network request failed
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static List<FaceStatus> getFaceList(Face forwarder) throws IOException, ManagementException {
-    Data data = retrieveDataSet(forwarder, new Name("/localhost/nfd/faces/list"));
-    return StatusDataset.wireDecode(data.getContent(), FaceStatus.class);
-  }
-
-  /**
-   * Retrieve a list of FIB entries and their NextHopRecords from the given
-   * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
-   * non-local packets are dropped).
-   *
-   * @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 IOException if the network request failed
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static List<FibEntry> getFibList(Face forwarder) throws IOException, ManagementException {
-    Data data = retrieveDataSet(forwarder, new Name("/localhost/nfd/fib/list"));
-    return StatusDataset.wireDecode(data.getContent(), FibEntry.class);
-  }
-
-  /**
-   * Retrieve a list of routing entries from the RIB; calls
-   * /localhost/nfd/rib/list which requires a local Face (all non-local packets
-   * are dropped).
-   *
-   * @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 IOException if the network request failed
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static List<RibEntry> getRouteList(Face forwarder) throws IOException, ManagementException {
-    Data data = retrieveDataSet(forwarder, new Name("/localhost/nfd/rib/list"));
-    return StatusDataset.wireDecode(data.getContent(), RibEntry.class);
-  }
-
-  /**
-   * Retrieve the list of strategy choice entries from the NFD; calls
-   * /localhost/nfd/rib/list which requires a local Face (all non-local packets
-   * are dropped).
-   *
-   * @param forwarder only a localhost Face
-   * @return a list of strategy choice entries, i.e. routes, see
-   * http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice.
-   * @throws IOException if the network request failed
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static List<StrategyChoice> getStrategyList(Face forwarder) throws IOException, ManagementException {
-    Data data = retrieveDataSet(forwarder, new Name("/localhost/nfd/strategy-choice/list"));
-    return StatusDataset.wireDecode(data.getContent(), StrategyChoice.class);
-  }
-
-  /**
-   * Retrieve the {@link KeyLocator} for an NFD.
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @return the {@link KeyLocator} of the NFD's key
-   * @throws IOException if the network request failed
-   * @throws ManagementException if the NFD rejected the request or no
-   * KeyLocator was found
-   */
-  public static KeyLocator getKeyLocator(Face forwarder) throws ManagementException, IOException {
-    Data data = retrieveStatus(forwarder);
-    if (!KeyLocator.canGetFromSignature(data.getSignature())) {
-      throw new ManagementException("No key locator available.");
-    }
-    return KeyLocator.getFromSignature(data.getSignature());
-  }
-
-  /**
-   * Helper method to register a new face on the forwarder; as mentioned at
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>,
-   * this is more for debugging; use 'register' instead
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @param faceId the ID of the face to add, see
-   * {@link #createFace(net.named_data.jndn.Face, java.lang.String)} for
-   * creating this
-   * @param prefix the {@link Name} of the next-hop prefix
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void addNextHop(Face forwarder, int faceId, Name prefix) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/fib/add-nexthop");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setName(prefix);
-    parameters.setFaceId(faceId);
-    command.append(parameters.wireEncode());
-
-    // send the interest
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Create a new face on the given forwarder. Ensure the forwarding face is on
-   * 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 {@link Face}
-   * @param uri a string like "tcp4://host.name.com" (see nfd-status channels
-   * for more protocol options)
-   * @return the newly created face ID
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static int createFace(Face forwarder, String uri) throws IOException, EncodingException, ManagementException {
-    Name command = new Name("/localhost/nfd/faces/create");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setUri(uri);
-    command.append(parameters.wireEncode());
-
-    // send the interest
-    ControlResponse response = sendCommand(forwarder, new Interest(command));
-
-    // return
-    return response.getBody().get(0).getFaceId();
-  }
-
-  /**
-   * Destroy a face on given forwarder. Ensure the forwarding face is on 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 {@link Face}
-   * @param faceId the ID of the face to destroy
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void destroyFace(Face forwarder, int faceId) throws IOException, EncodingException, ManagementException {
-    Name command = new Name("/localhost/nfd/faces/destroy");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setFaceId(faceId);
-    command.append(parameters.wireEncode());
-
-    // send the interest
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Enable a local control feature on the given forwarder. See
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature">http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature</a>
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @param header the control feature to enable
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void enableLocalControlHeader(Face forwarder, LocalControlHeader header) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/faces/enable-local-control");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setLocalControlFeature(header.getNumericValue());
-    command.append(parameters.wireEncode());
-
-    // send command and return
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Disable a local control feature on the given forwarder. See
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature">http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature</a>
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @param header the control feature to disable
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void disableLocalControlHeader(Face forwarder, LocalControlHeader header) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/faces/disable-local-control");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setLocalControlFeature(header.getNumericValue());
-    command.append(parameters.wireEncode());
-
-    // send command and return
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Register a route on the forwarder; see
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
-   * for command-line usage and
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
-   * for protocol documentation. Ensure the forwarding face is on 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 {@link Face}
-   * @param controlParameters the {@link ControlParameters} command options
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void register(Face forwarder, ControlParameters controlParameters) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/rib/register");
-    command.append(controlParameters.wireEncode());
-
-    // send the interest
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Register a route on a forwarder; this will create a new face on the
-   * forwarder to the given URI/route pair. See register(Face,
-   * ControlParameters) for more detailed documentation.
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @param uri the URI (e.g. "tcp4://10.10.2.2:6363") of the remote node; note
-   * that this must be one of the canonical forms described in the wiki
-   * (http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#TCP) for NFD to
-   * accept the registration--otherwise you will see 400 errors
-   * @param route the {@link Name} prefix of the route
-   * @param cost the numeric cost of forwarding along the route
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void register(Face forwarder, String uri, Name route, int cost) throws IOException, EncodingException, ManagementException {
-    // create the new face
-    int faceId = createFace(forwarder, uri);
-
-    // run base method
-    register(forwarder, faceId, route, cost);
-  }
-
-  /**
-   * Register a route on a forwarder; this will not create a new face since it
-   * is provided a faceId. See register(Face, ControlParameters) for full
-   * documentation.
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @param faceId the ID of the {@link Face} to assign to the route
-   * @param route the {@link Name} prefix of the route
-   * @param cost the numeric cost of forwarding along the route
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void register(Face forwarder, int faceId, Name route, int cost) throws IOException, EncodingException, ManagementException {
-    // build command name
-    ControlParameters parameters = new ControlParameters();
-    parameters.setName(route);
-    parameters.setFaceId(faceId);
-    parameters.setCost(cost);
-    ForwardingFlags flags = new ForwardingFlags();
-    flags.setCapture(true);
-    flags.setChildInherit(true);
-    parameters.setForwardingFlags(flags);
-
-    // run base method
-    register(forwarder, parameters);
-  }
-
-  /**
-   * Unregister a route on a forwarder; see
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
-   * for command-line usage and
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
-   * for protocol documentation. Ensure the forwarding face is on 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 {@link Face}
-   * @param controlParameters the {@link ControlParameters} command options
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void unregister(Face forwarder, ControlParameters controlParameters) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/rib/unregister");
-    command.append(controlParameters.wireEncode());
-
-    // send the interest
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Unregister a route on a forwarder; see
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
-   * for command-line usage and
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
-   * for protocol documentation. Ensure the forwarding face is on 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 {@link Face}
-   * @param route the {@link Name} prefix of the route
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void unregister(Face forwarder, Name route) throws IOException, EncodingException, ManagementException {
-    // build command name
-    ControlParameters controlParameters = new ControlParameters();
-    controlParameters.setName(route);
-
-    // send the interest
-    unregister(forwarder, controlParameters);
-  }
-
-  /**
-   * Unregister a route on a forwarder; see
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
-   * for command-line usage and
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
-   * for protocol documentation. Ensure the forwarding face is on 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 {@link Face}
-   * @param route the {@link Name} prefix of the route
-   * @param faceId the specific ID of the face to remove (more than one face can
-   * be registered to a route)
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void unregister(Face forwarder, Name route, int faceId) throws IOException, EncodingException, ManagementException {
-    // build command name
-    ControlParameters controlParameters = new ControlParameters();
-    controlParameters.setName(route);
-    controlParameters.setFaceId(faceId);
-
-    // send the interest
-    unregister(forwarder, controlParameters);
-  }
-
-  /**
-   * Unregister a route on a forwarder; see
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
-   * for command-line usage and
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
-   * for protocol documentation. Ensure the forwarding face is on 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 {@link Face}
-   * @param route the {@link Name} prefix of the route
-   * @param uri the URI (e.g. "tcp4://some.host.com") of the remote node (more
-   * than one face can be registered to a route)
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void unregister(Face forwarder, Name route, String uri) throws IOException, EncodingException, ManagementException {
-    int faceId = -1;
-    for (FaceStatus face : getFaceList(forwarder)) {
-      if (face.getUri().matches(uri)) {
-        faceId = face.getFaceId();
-        break;
-      }
-    }
-
-    if (faceId == -1) {
-      throw new ManagementException("Face not found: " + uri);
-    }
-
-    // send the interest
-    unregister(forwarder, route, faceId);
-  }
-
-  /**
-   * Set a strategy on the forwarder; see
-   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
-   * for command-line usage and
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice">http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice</a>
-   * for protocol documentation. Ensure the forwarding face is on 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 {@link Face}
-   * @param prefix the {@link Name} prefix
-   * @param strategy the {@link Name} of the strategy to set, e.g.
-   * /localhost/nfd/strategy/broadcast
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void setStrategy(Face forwarder, Name prefix, Name strategy) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/strategy-choice/set");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setName(prefix);
-    parameters.setStrategy(strategy);
-    command.append(parameters.wireEncode());
-
-    // send the interest
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Set a strategy on the forwarder; see
-   * {@link #setStrategy(net.named_data.jndn.Face, net.named_data.jndn.Name, net.named_data.jndn.Name)}
-   * for more information. Ensure the forwarding face is on 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 {@link Face}
-   * @param prefix the {@link Name} prefix
-   * @throws IOException if the network request failed
-   * @throws EncodingException if the NFD response could not be decoded
-   * @throws ManagementException if the NFD rejected the request
-   */
-  public static void unsetStrategy(Face forwarder, Name prefix) throws IOException, EncodingException, ManagementException {
-    // build command name
-    Name command = new Name("/localhost/nfd/strategy-choice/unset");
-    ControlParameters parameters = new ControlParameters();
-    parameters.setName(prefix);
-    command.append(parameters.wireEncode());
-
-    // send the interest
-    sendCommand(forwarder, new Interest(command));
-  }
-
-  /**
-   * Build an interest to retrieve the NFD status.
-   *
-   * @param forwarder only a localhost {@link Face}
-   * @return the status {@link Data} packet
-   * @throws IOException if the retrieval fails
-   */
-  private static Data retrieveStatus(Face forwarder) throws IOException {
-    Interest interest = new Interest(new Name("/localhost/nfd/status"));
-    interest.setMustBeFresh(true);
-    interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
-    interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
-    Data data = SimpleClient.getDefault().getSync(forwarder, interest);
-    return data;
-  }
-
-  /**
-   * Build an interest to retrieve a segmented data set from the NFD; for
-   * details on the DataSet, see
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
-   *
-   * @param forwarder the {@link Face} to an NFD
-   * @param datasetName the {@link Name} of the dataset to retrieve
-   * @return the re-assembled {@link Data} packet
-   * @throws IOException if the request fails
-   * @throws ManagementException if the returned TLV is not the expected type
-   */
-  public static Data retrieveDataSet(Face forwarder, Name datasetName) throws IOException, ManagementException {
-    // build management Interest packet; see <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
-    Interest interest = new Interest(datasetName);
-    interest.setMustBeFresh(true);
-    interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
-    interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
-
-    // send packet
-    Data data = AdvancedClient.getDefault().getSync(forwarder, interest);
-
-    // check for failed request
-    if (data.getContent().buf().get(0) == ControlResponse.TLV_CONTROL_RESPONSE) {
-      throw ManagementException.fromResponse(data.getContent());
-    }
-
-    return data;
-  }
-
-  /**
-   * Send an interest as a command to the forwarder; this method will convert
-   * the interest to a command interest and block until a response is received
-   * from the forwarder. Ensure the forwarding face is on 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, command signing info must be set
-   * @param interest As described at
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/ControlCommand,">http://redmine.named-data.net/projects/nfd/wiki/ControlCommand,</a>
-   * the requested interest must have encoded ControlParameters appended to the
-   * interest name
-   * @return a {@link ControlResponse}
-   * @throws java.io.IOException
-   * @throws net.named_data.jndn.encoding.EncodingException
-   * @throws com.intel.jndn.management.ManagementException
-   */
-  public static ControlResponse sendCommand(Face forwarder, Interest interest) throws IOException, EncodingException, ManagementException {
-    // forwarder must have command signing info set
-    try {
-      forwarder.makeCommandInterest(interest);
-    } catch (SecurityException e) {
-      throw new IllegalArgumentException("Failed to make command interest; ensure command signing info is set on the face.", e);
-    }
-
-    // send command packet
-    Data data = SimpleClient.getDefault().getSync(forwarder, interest);
-
-    // decode response
-    ControlResponse response = new ControlResponse();
-    response.wireDecode(data.getContent().buf());
-
-    // check response for success
-    if (response.getStatusCode() != OK_STATUS) {
-      throw ManagementException.fromResponse(response);
-    }
-
-    return response;
-  }
-}
diff --git a/src/main/java/com/intel/jndn/management/NdnPingClient.java b/src/main/java/com/intel/jndn/management/NdnPingClient.java
new file mode 100644
index 0000000..ecdaecc
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/NdnPingClient.java
@@ -0,0 +1,73 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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;
+
+import com.intel.jndn.management.helpers.FetchHelper;
+import net.named_data.jndn.Data;
+import net.named_data.jndn.Face;
+import net.named_data.jndn.Interest;
+import net.named_data.jndn.Name;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class NdnPingClient {
+  public static final long DEFAULT_TIMEOUT = 2000;
+  private static final Logger LOG = Logger.getLogger(NdnPingClient.class.getName());
+
+  /**
+   * Prevent creation of NdnPingClient instances
+   */
+  private NdnPingClient() {
+  }
+
+  /**
+   * Ping a forwarder on an existing face to verify that the forwarder is
+   * working and responding to requests; this version sends a discovery packet
+   * to /localhost/nfd which should always respond if the requestor is on the
+   * same machine as the NDN forwarding daemon.
+   *
+   * @param face only a localhost Face
+   * @return true if successful, false otherwise
+   */
+  public static boolean pingLocal(Face face) {
+    return ping(face, new Name("/localhost/nfd"));
+  }
+
+  /**
+   * Request a name on an existing face to verify the forwarder is working and
+   * responding to requests. Note that the name must be served or cached on the
+   * forwarder for this to return true.
+   *
+   * @param face a {@link Face} to ping
+   * @param name a known {@link Name} that the remote node will answer to
+   * @return true if successful, false otherwise
+   */
+  public static boolean ping(Face face, Name name) {
+    // build interest
+    Interest interest = new Interest(name);
+    interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
+    interest.setMustBeFresh(true);
+
+    // send packet
+    try {
+      Data data = FetchHelper.getData(face, interest);
+      return data != null;
+    } catch (IOException e) {
+      LOG.log(Level.INFO, "Error sending ping interest", e);
+      return false;
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/Nfdc.java b/src/main/java/com/intel/jndn/management/Nfdc.java
new file mode 100644
index 0000000..ae94417
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/Nfdc.java
@@ -0,0 +1,573 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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;
+
+import com.intel.jndn.management.enums.RouteOrigin;
+import com.intel.jndn.management.helpers.FetchHelper;
+import com.intel.jndn.management.helpers.StatusDatasetHelper;
+import net.named_data.jndn.*;
+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.enums.LocalControlHeader;
+import com.intel.jndn.management.types.RibEntry;
+import com.intel.jndn.management.types.StrategyChoice;
+import java.io.IOException;
+import java.util.List;
+
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.security.SecurityException;
+
+/**
+ * Helper class for interacting with an NDN forwarder daemon; see
+ * <a href="http://redmine.named-data.net/projects/nfd/wiki/Management">NFD Management</a>
+ * for explanations of the various protocols used.
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class Nfdc {
+  private static final int OK_STATUS = 200;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Prevent creation of Nfdc instances
+   */
+  private Nfdc() {
+  }
+
+  /**
+   * Retrieve the status of the given forwarder; calls /localhost/nfd/status/general
+   * which requires a local Face (all non-local packets are dropped)
+   *
+   * @param face only a localhost Face
+   * @return the forwarder status object
+   *
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus">ForwarderStatus</a>
+   * @throws ManagementException if the network request failed or the returned status could not be decoded
+   */
+  public static ForwarderStatus getForwarderStatus(Face face) throws ManagementException {
+    try {
+      List<Data> segments = FetchHelper.getSegmentedData(face, new Name("/localhost/nfd/status/general"));
+      return new ForwarderStatus(StatusDatasetHelper.combine(segments));
+    } catch (IOException|EncodingException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * 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 face only a localhost Face
+   * @return a list of face status objects
+   *
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt">FaceManagement</a>
+   * @throws ManagementException if the network request failed or if the NFD rejected the request
+   */
+  public static List<FaceStatus> getFaceList(Face face) throws ManagementException {
+    try {
+      List<Data> segments = FetchHelper.getSegmentedData(face, new Name("/localhost/nfd/faces/list"));
+      return StatusDatasetHelper.wireDecode(segments, FaceStatus.class);
+    } catch (IOException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Retrieve a list of FIB entries and their NextHopRecords from the given
+   * forwarder; calls /localhost/nfd/fib/list which requires a local Face (all
+   * non-local packets are dropped).
+   *
+   * @param face only a localhost Face
+   * @return a list of FIB entries
+   *
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset">FIB Dataset</a>
+   * @throws ManagementException if the network request failed or if the NFD rejected the request
+   */
+  public static List<FibEntry> getFibList(Face face) throws ManagementException {
+    try {
+      List<Data> segments = FetchHelper.getSegmentedData(face, new Name("/localhost/nfd/fib/list"));
+      return StatusDatasetHelper.wireDecode(segments, FibEntry.class);
+    } catch (IOException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Retrieve a list of routing entries from the RIB; calls
+   * /localhost/nfd/rib/list which requires a local Face (all non-local packets
+   * are dropped).
+   *
+   * @param face only a localhost Face
+   * @return a list of RIB entries, i.e. routes
+   *
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset">RIB Dataset</a>
+   * @throws ManagementException if the network request failed or if the NFD rejected the request
+   */
+  public static List<RibEntry> getRouteList(Face face) throws ManagementException {
+    try {
+      List<Data> segments = FetchHelper.getSegmentedData(face, new Name("/localhost/nfd/rib/list"));
+      return StatusDatasetHelper.wireDecode(segments, RibEntry.class);
+    } catch (IOException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Retrieve the list of strategy choice entries from the NFD; calls
+   * /localhost/nfd/rib/list which requires a local Face (all non-local packets
+   * are dropped).
+   *
+   * @param face only a localhost Face
+   * @return a list of strategy choice entries, i.e. routes
+   *
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice">StrategyChoice</a>
+   * @throws ManagementException  if the network request failed, the NFD response could not be decoded, or
+   *                              the NFD rejected the request
+   */
+  public static List<StrategyChoice> getStrategyList(Face face) throws ManagementException {
+    try {
+      List<Data> segments = FetchHelper.getSegmentedData(face, new Name("/localhost/nfd/strategy-choice/list"));
+      return StatusDatasetHelper.wireDecode(segments, StrategyChoice.class);
+    } catch (IOException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Retrieve the {@link KeyLocator} for an NFD.
+   *
+   * @param face only a localhost {@link Face}
+   * @return the {@link KeyLocator} of the NFD's key
+   * @throws ManagementException if the network request failed, if the NFD rejected the request, or no
+   *                             KeyLocator was found
+   */
+  public static KeyLocator getKeyLocator(Face face) throws ManagementException {
+    try {
+      List<Data> segments = FetchHelper.getSegmentedData(face, new Name("/localhost/nfd/status/general"));
+      if (segments.isEmpty() || !KeyLocator.canGetFromSignature(segments.get(0).getSignature())) {
+        throw new ManagementException("No key locator available.");
+      }
+      return KeyLocator.getFromSignature(segments.get(0).getSignature());
+    } catch (IOException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Create a new face on the given forwarder. Ensure the forwarding face is on
+   * the local machine (management requests are to /localhost/...) and that
+   * command signing has been set up (e.g. forwarder.setCommandSigningInfo()).
+   *
+   * @param face only a localhost {@link Face}
+   * @param uri       a string like "tcp4://host.name.com" (see nfd-status channels
+   *                  for more protocol options)
+   * @return the newly created face ID
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static int createFace(Face face, String uri) throws ManagementException {
+    Name command = new Name("/localhost/nfd/faces/create");
+    ControlParameters parameters = new ControlParameters();
+    parameters.setUri(uri);
+    command.append(parameters.wireEncode());
+
+    try {
+      // send the interest
+      ControlResponse response = sendCommand(face, command);
+
+      // return
+      return response.getBody().get(0).getFaceId();
+    }
+    catch (IOException|EncodingException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Destroy a face on given forwarder. Ensure the forwarding face is on the
+   * local machine (management requests are to /localhost/...) and that command
+   * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
+   *
+   * @param face only a localhost {@link Face}
+   * @param faceId    the ID of the face to destroy
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void destroyFace(Face face, int faceId) throws ManagementException {
+    Name command = new Name("/localhost/nfd/faces/destroy");
+    ControlParameters parameters = new ControlParameters();
+    parameters.setFaceId(faceId);
+    command.append(parameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Enable a local control feature on the given forwarder. See
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature">http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Enable-a-LocalControlHeader-feature</a>
+   *
+   * @param face only a localhost {@link Face}
+   * @param header    the control feature to enable
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void enableLocalControlHeader(Face face, LocalControlHeader header) throws ManagementException {
+    // build command name
+    Name command = new Name("/localhost/nfd/faces/enable-local-control");
+    ControlParameters parameters = new ControlParameters();
+    parameters.setLocalControlFeature(header.toInteger());
+    command.append(parameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Disable a local control feature on the given forwarder. See
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature">http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Disable-a-LocalControlHeader-feature</a>
+   *
+   * @param face only a localhost {@link Face}
+   * @param header    the control feature to disable
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void disableLocalControlHeader(Face face, LocalControlHeader header) throws ManagementException {
+    // build command name
+    Name command = new Name("/localhost/nfd/faces/disable-local-control");
+    ControlParameters parameters = new ControlParameters();
+    parameters.setLocalControlFeature(header.toInteger());
+    command.append(parameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Register a route on the forwarder; see
+   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
+   * for command-line usage and
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
+   * for protocol documentation. Ensure the forwarding face is on the local
+   * machine (management requests are to /localhost/...) and that command
+   * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
+   *
+   * @param face         only a localhost {@link Face}
+   * @param controlParameters the {@link ControlParameters} command options
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void register(Face face, ControlParameters controlParameters) throws ManagementException {
+    // build command name
+    Name command = new Name("/localhost/nfd/rib/register");
+    command.append(controlParameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Register a route on a forwarder; this will create a new face on the
+   * forwarder towards the face (e.g., self registration)
+   *
+   * @param face only a localhost {@link Face}
+   * @param route     the {@link Name} prefix of the route
+   * @param cost      the numeric cost of forwarding along the route
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void register(Face face, Name route, int cost) throws ManagementException {
+    ForwardingFlags flags = new ForwardingFlags();
+    flags.setCapture(false);
+    flags.setChildInherit(true);
+
+    register(face, new ControlParameters()
+      .setName(route)
+      .setCost(cost)
+      .setOrigin(RouteOrigin.APP.toInteger())
+      .setForwardingFlags(flags));
+  }
+  /**
+   * Register a route on a forwarder; this will create a new face on the
+   * forwarder to the given URI/route pair. See register(Face,
+   * ControlParameters) for more detailed documentation.
+   *
+   * @param face only a localhost {@link Face}
+   * @param uri       the URI (e.g. "tcp4://10.10.2.2:6363") of the remote node; note
+   *                  that this must be one of the canonical forms described in the wiki
+   *                  (http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#TCP) for NFD to
+   *                  accept the registration--otherwise you will see 400 errors
+   * @param route     the {@link Name} prefix of the route
+   * @param cost      the numeric cost of forwarding along the route
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void register(Face face, String uri, Name route, int cost) throws ManagementException {
+    // create the new face
+    int faceId = createFace(face, uri);
+
+    // run base method
+    register(face, faceId, route, cost);
+  }
+
+  /**
+   * Register a route on a forwarder; this will not create a new face since it
+   * is provided a faceId. See register(Face, ControlParameters) for full
+   * documentation.
+   *
+   * @param forwarder only a localhost {@link Face}
+   * @param faceId    the ID of the {@link Face} to assign to the route
+   * @param route     the {@link Name} prefix of the route
+   * @param cost      the numeric cost of forwarding along the route
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void register(Face forwarder, int faceId, Name route, int cost) throws ManagementException {
+    // build command name
+    ControlParameters parameters = new ControlParameters();
+    parameters.setName(route);
+    parameters.setFaceId(faceId);
+    parameters.setCost(cost);
+    parameters.setOrigin(RouteOrigin.STATIC.toInteger());
+    ForwardingFlags flags = new ForwardingFlags();
+    flags.setCapture(false);
+    flags.setChildInherit(true);
+    parameters.setForwardingFlags(flags);
+
+    // run base method
+    register(forwarder, parameters);
+  }
+
+  /**
+   * Unregister a route on a forwarder; see
+   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
+   * for command-line usage and
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
+   * for protocol documentation. Ensure the forwarding face is on the local
+   * machine (management requests are to /localhost/...) and that command
+   * signing has been set up (e.g. forwarder.setCommandSigningInfo()).
+   *
+   * @param face         only a localhost {@link Face}
+   * @param controlParameters the {@link ControlParameters} command options
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void unregister(Face face, ControlParameters controlParameters) throws ManagementException {
+    // build command name
+    Name command = new Name("/localhost/nfd/rib/unregister");
+    command.append(controlParameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Unregister a route on a forwarder; see
+   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
+   * for command-line usage and
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
+   * for protocol documentation. Ensure the forwarding face is on the local
+   * machine (management requests are to /localhost/...) and that command
+   * signing has been set up (e.g. forwarder.setCommandSigningInfo().
+   *
+   * @param face only a localhost {@link Face}
+   * @param route     the {@link Name} prefix of the route
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void unregister(Face face, Name route) throws ManagementException {
+    // build command name
+    ControlParameters controlParameters = new ControlParameters();
+    controlParameters.setName(route);
+
+    // send the interest
+    unregister(face, controlParameters);
+  }
+
+  /**
+   * Unregister a route on a forwarder; see
+   * <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">http://named-data.net/doc/NFD/current/manpages/nfdc.html</a>
+   * for command-line usage and
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt</a>
+   * for protocol documentation. Ensure the forwarding face is on the local
+   * machine (management requests are to /localhost/...) and that command
+   * signing has been set up (e.g. forwarder.setCommandSigningInfo().
+   *
+   * @param face only a localhost {@link Face}
+   * @param route     the {@link Name} prefix of the route
+   * @param faceId    the specific ID of the face to remove (more than one face can
+   *                  be registered to a route)
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void unregister(Face face, Name route, int faceId) throws ManagementException {
+    // build command name
+    ControlParameters controlParameters = new ControlParameters();
+    controlParameters.setName(route);
+    controlParameters.setFaceId(faceId);
+
+    // send the interest
+    unregister(face, controlParameters);
+  }
+
+  /**
+   * Unregister a route on a forwarder
+   *
+   * Ensure the forwarding face is on the local machine (management requests are to /localhost/...) and that command
+   * signing has been set up using forwarder.setCommandSigningInfo().
+   *
+   * @param face only a localhost {@link Face}
+   * @param route     the {@link Name} prefix of the route
+   * @param uri       the URI (e.g. "tcp4://some.host.com") of the remote node (more
+   *                  than one face can be registered to a route)
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   * @see <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">nfdc command-line usage</a>
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">RibMgmt</a>
+   */
+  public static void unregister(Face face, Name route, String uri) throws ManagementException {
+    int faceId = -1;
+    for (FaceStatus faceStatus : getFaceList(face)) {
+      if (faceStatus.getRemoteUri().matches(uri)) {
+        faceId = faceStatus.getFaceId();
+        break;
+      }
+    }
+
+    if (faceId == -1) {
+      throw new ManagementException("Face not found: " + uri);
+    }
+
+    // send the interest
+    unregister(face, route, faceId);
+  }
+
+  /**
+   * Set a strategy on the forwarder
+   *
+   * Ensure the forwarding face is on the local machine (management requests are to /localhost/...) and that command
+   * signing has been set up using forwarder.setCommandSigningInfo().
+   *
+   * @param face only a localhost {@link Face}
+   * @param prefix    the {@link Name} prefix
+   * @param strategy  the {@link Name} of the strategy to set, e.g.
+   *                  /localhost/nfd/strategy/broadcast
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   * @see <a href="http://named-data.net/doc/NFD/current/manpages/nfdc.html">nfdc command-line usage</a>
+   * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice">StrategyChoice</a>
+   */
+  public static void setStrategy(Face face, Name prefix, Name strategy) throws ManagementException {
+    // build command name
+    Name command = new Name("/localhost/nfd/strategy-choice/set");
+    ControlParameters parameters = new ControlParameters();
+    parameters.setName(prefix);
+    parameters.setStrategy(strategy);
+    command.append(parameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Set a strategy on the forwarder; see
+   * {@link #setStrategy(net.named_data.jndn.Face, net.named_data.jndn.Name, net.named_data.jndn.Name)}
+   * for more information. Ensure the forwarding face is on the local machine
+   * (management requests are to /localhost/...) and that command signing has
+   * been set up (e.g. forwarder.setCommandSigningInfo()).
+   *
+   * @param face only a localhost {@link Face}
+   * @param prefix    the {@link Name} prefix
+   * @throws ManagementException if the network request failed, the NFD response could not be decoded, or
+   *                             the NFD rejected the request
+   */
+  public static void unsetStrategy(Face face, Name prefix) throws ManagementException {
+    // build command name
+    Name command = new Name("/localhost/nfd/strategy-choice/unset");
+    ControlParameters parameters = new ControlParameters();
+    parameters.setName(prefix);
+    command.append(parameters.wireEncode());
+
+    try {
+      sendCommand(face, command);
+    } catch (IOException|EncodingException|ManagementException e) {
+      throw new ManagementException(e.getMessage(), e);
+    }
+  }
+
+  /**
+   * Send an interest as a command to the forwarder; this method will convert
+   * the interest to a command interest and block until a response is received
+   * from the forwarder. Ensure the forwarding face is on the local machine
+   * (management requests are to /localhost/...) and that command signing has
+   * been set up (e.g. forwarder.setCommandSigningInfo()).
+   *
+   * @param face only a localhost Face, command signing info must be set
+   * @param name As described at
+   *             <a href="http://redmine.named-data.net/projects/nfd/wiki/ControlCommand,">http://redmine.named-data.net/projects/nfd/wiki/ControlCommand,</a>
+   *             the requested interest must have encoded ControlParameters appended to the
+   *             interest name
+   * @return a {@link ControlResponse}
+   * @throws java.io.IOException
+   * @throws net.named_data.jndn.encoding.EncodingException
+   * @throws ManagementException
+   */
+  private static ControlResponse
+  sendCommand(Face face, Name name) throws IOException, EncodingException, ManagementException {
+    Interest interest = new Interest(name);
+
+    // forwarder must have command signing info set
+    try {
+      face.makeCommandInterest(interest);
+    } catch (SecurityException e) {
+      throw new IllegalArgumentException("Failed to make command interest; ensure command signing info is set on the face.", e);
+    }
+
+    // send command packet
+    Data data = FetchHelper.getData(face, interest.getName());
+
+    // decode response
+    ControlResponse response = new ControlResponse();
+    response.wireDecode(data.getContent().buf());
+
+    // check response for success
+    if (response.getStatusCode() != OK_STATUS) {
+      throw ManagementException.fromResponse(response);
+    }
+
+    return response;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/enums/FacePersistency.java b/src/main/java/com/intel/jndn/management/enums/FacePersistency.java
new file mode 100644
index 0000000..08630b8
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/enums/FacePersistency.java
@@ -0,0 +1,54 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.enums;
+
+/**
+ * Indicate whether the face is persistent; used by FaceStatus
+ *
+ * @see <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">FaceMgmt</a>
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public enum FacePersistency {
+  NONE(-1), // invalid value
+
+  PERSISTENT(0),
+  ON_DEMAND(1),
+  PERMANENT(2);
+
+  private final int value;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  FacePersistency(int value) {
+    this.value = value;
+  }
+
+  public final int toInteger() {
+    return value;
+  }
+
+  public static FacePersistency
+  fromInteger(int value) {
+    switch (value) {
+      case 0:
+        return PERSISTENT;
+      case 1:
+        return ON_DEMAND;
+      case 2:
+        return PERMANENT;
+      default:
+        return NONE;
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/enums/FaceScope.java b/src/main/java/com/intel/jndn/management/enums/FaceScope.java
new file mode 100644
index 0000000..d32621e
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/enums/FaceScope.java
@@ -0,0 +1,53 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.enums;
+
+/**
+ * Indicate whether the face is local for scope control purposes; used by
+ * FaceStatus
+ *
+ * @see <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">FaceMgmt</a>
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public enum FaceScope {
+
+  NONE(-1), // invalid value
+
+  NON_LOCAL(0),
+  LOCAL(1);
+
+  private final int value;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  FaceScope(int value) {
+    this.value = value;
+  }
+
+  public final int toInteger() {
+    return value;
+  }
+
+  public static FaceScope
+  fromInteger(int value) {
+    switch (value) {
+      case 0:
+        return NON_LOCAL;
+      case 1:
+        return LOCAL;
+      default:
+        return NONE;
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/enums/LinkType.java b/src/main/java/com/intel/jndn/management/enums/LinkType.java
new file mode 100644
index 0000000..99da791
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/enums/LinkType.java
@@ -0,0 +1,57 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.enums;
+
+/**
+ * NFD face link type
+ * @see <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">FaceMgmt</a>
+ */
+public enum LinkType {
+
+  NONE(-1), // invalid value
+
+  /**
+   * Link is point-to-point
+   */
+  POINT_TO_POINT(0),
+
+  /**
+   * Link is multi-access
+   */
+  MULTI_ACCESS(1);
+
+  private final int value;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  LinkType(int value) {
+    this.value = value;
+  }
+
+  public final int toInteger() {
+    return value;
+  }
+
+  public static LinkType
+  fromInteger(int value) {
+    switch (value) {
+      case 0:
+        return POINT_TO_POINT;
+      case 1:
+        return MULTI_ACCESS;
+      default:
+        return NONE;
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/types/LocalControlHeader.java b/src/main/java/com/intel/jndn/management/enums/LocalControlHeader.java
similarity index 81%
rename from src/main/java/com/intel/jndn/management/types/LocalControlHeader.java
rename to src/main/java/com/intel/jndn/management/enums/LocalControlHeader.java
index 5ca393f..86a205d 100644
--- a/src/main/java/com/intel/jndn/management/types/LocalControlHeader.java
+++ b/src/main/java/com/intel/jndn/management/enums/LocalControlHeader.java
@@ -11,7 +11,7 @@
  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  * more details.
  */
-package com.intel.jndn.management.types;
+package com.intel.jndn.management.enums;
 
 /**
  * Define constants for local control header options. See
@@ -25,12 +25,15 @@
   NEXT_HOP_FACE_ID(2),
   CACHING_POLICY(3);
 
+  private final int value;
+
+  /////////////////////////////////////////////////////////////////////////////
+
   LocalControlHeader(int value) {
-    value_ = value;
+    this.value = value;
   }
 
-  public final int getNumericValue() {
-    return value_;
+  public final int toInteger() {
+    return value;
   }
-  private final int value_;
 }
diff --git a/src/main/java/com/intel/jndn/management/enums/NfdTlv.java b/src/main/java/com/intel/jndn/management/enums/NfdTlv.java
new file mode 100644
index 0000000..d414ad2
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/enums/NfdTlv.java
@@ -0,0 +1,94 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.enums;
+
+/**
+ * NFD Management protocol TLV codes
+ */
+public class NfdTlv {
+  /**
+   * Prevent creation of NfdTlv instances
+   */
+  private NfdTlv() {
+  }
+
+  // ControlParameters
+  // http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
+  public static final int ControlParameters   = 104;
+  public static final int FaceId              = 105;
+  public static final int Uri                 = 114;
+  public static final int LocalControlFeature = 110;
+  public static final int Origin              = 111;
+  public static final int Cost                = 106;
+  public static final int Flags               = 108;
+  public static final int Strategy            = 107;
+  public static final int ExpirationPeriod    = 109;
+
+  // ControlResponse
+  // http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
+  public static final int ControlResponse = 101;
+  public static final int StatusCode      = 102;
+  public static final int StatusText      = 103;
+
+  // ForwarderStatus
+  // http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus
+  public static final int NfdVersion           = 128;
+  public static final int StartTimestamp       = 129;
+  public static final int CurrentTimestamp     = 130;
+  public static final int NNameTreeEntries     = 131;
+  public static final int NFibEntries          = 132;
+  public static final int NPitEntries          = 133;
+  public static final int NMeasurementsEntries = 134;
+  public static final int NCsEntries           = 135;
+
+  // Face Management
+  // http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt
+  public static final int FaceStatus            = 128;
+  public static final int LocalUri              = 129;
+  public static final int ChannelStatus         = 130;
+  public static final int UriScheme             = 131;
+  public static final int FaceScope             = 132;
+  public static final int FacePersistency       = 133;
+  public static final int LinkType              = 134;
+  public static final int FaceQueryFilter       = 150;
+  public static final int FaceEventNotification = 192;
+  public static final int FaceEventKind         = 193;
+
+  // ForwarderStatus and FaceStatus counters
+  // http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus
+  // http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt
+  public static final int NInInterests  = 144;
+  public static final int NInDatas      = 145;
+  public static final int NInNacks      = 151;
+  public static final int NOutInterests = 146;
+  public static final int NOutDatas     = 147;
+  public static final int NOutNacks     = 152;
+  public static final int NInBytes      = 148;
+  public static final int NOutBytes     = 149;
+
+  // FIB Management
+  // http://redmine.named-data.net/projects/nfd/wiki/FibMgmt
+  public static final int FibEntry      = 128;
+  public static final int NextHopRecord = 129;
+
+  // Strategy Choice Management
+  // http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
+  public static final int StrategyChoice = 128;
+
+  // RIB Management
+  // http://redmine.named-data.net/projects/nfd/wiki/RibMgmt
+  public static final int RibEntry = 128;
+  public static final int Route    = 129;
+}
diff --git a/src/main/java/com/intel/jndn/management/enums/RouteFlags.java b/src/main/java/com/intel/jndn/management/enums/RouteFlags.java
new file mode 100644
index 0000000..334a726
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/enums/RouteFlags.java
@@ -0,0 +1,36 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.enums;
+
+/**
+ * NFD route flags
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">RibMgmt</a>
+ */
+public enum RouteFlags {
+  NONE          (0),
+  CHILD_INHERIT (1),
+  CAPTURE       (2);
+
+  private final int value;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  RouteFlags(int value) {
+    this.value = value;
+  }
+
+  public final int toInteger() {
+    return value;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/enums/RouteOrigin.java b/src/main/java/com/intel/jndn/management/enums/RouteOrigin.java
new file mode 100644
index 0000000..6156276
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/enums/RouteOrigin.java
@@ -0,0 +1,60 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.enums;
+
+/**
+ * NFD route origin
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt">RibMgmt</a>
+ */
+public enum RouteOrigin {
+  UNKNOWN  (-1),
+  APP      (0),
+  AUTOREG  (64),
+  CLIENT   (65),
+  AUTOCONF (66),
+  NLSR     (128),
+  STATIC   (255);
+
+  private final int value;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  RouteOrigin(int value) {
+    this.value = value;
+  }
+
+  public final int toInteger() {
+    return value;
+  }
+
+  public static RouteOrigin
+  fromInteger(int value) {
+    switch (value) {
+      case 0:
+        return APP;
+      case 64:
+        return AUTOREG;
+      case 65:
+        return CLIENT;
+      case 66:
+        return AUTOCONF;
+      case 128:
+        return NLSR;
+      case 255:
+        return STATIC;
+      default:
+        return UNKNOWN;
+    }
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/Strategies.java b/src/main/java/com/intel/jndn/management/enums/Strategies.java
similarity index 92%
rename from src/main/java/com/intel/jndn/management/Strategies.java
rename to src/main/java/com/intel/jndn/management/enums/Strategies.java
index f8816be..f1a9908 100644
--- a/src/main/java/com/intel/jndn/management/Strategies.java
+++ b/src/main/java/com/intel/jndn/management/enums/Strategies.java
@@ -1,6 +1,6 @@
 /*
  * jndn-management
- * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2015-2016, 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,
@@ -11,7 +11,7 @@
  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  * more details.
  */
-package com.intel.jndn.management;
+package com.intel.jndn.management.enums;
 
 import net.named_data.jndn.Name;
 
diff --git a/src/main/java/com/intel/jndn/management/EncodingHelper.java b/src/main/java/com/intel/jndn/management/helpers/EncodingHelper.java
similarity index 94%
rename from src/main/java/com/intel/jndn/management/EncodingHelper.java
rename to src/main/java/com/intel/jndn/management/helpers/EncodingHelper.java
index b24241d..66e2c80 100644
--- a/src/main/java/com/intel/jndn/management/EncodingHelper.java
+++ b/src/main/java/com/intel/jndn/management/helpers/EncodingHelper.java
@@ -1,6 +1,6 @@
 /*
  * jndn-management
- * Copyright (c) 2015, Intel Corporation.
+ * Copyright (c) 2015-2016, 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,
@@ -11,9 +11,11 @@
  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  * more details.
  */
-package com.intel.jndn.management;
+package com.intel.jndn.management.helpers;
 
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
 import net.named_data.jndn.ControlParameters;
 import net.named_data.jndn.ForwardingFlags;
 import net.named_data.jndn.Name;
@@ -196,4 +198,14 @@
 
     encoder.writeTypeAndLength(Tlv.ControlParameters_ControlParameters, encoder.getLength() - saveLength);
   }
+
+  /**
+   * Convert ByteBuffer to string, assuming UTF-8 encoding in the buffer
+   */
+  public static String
+  toString(ByteBuffer buffer) {
+    byte[] array = new byte[buffer.remaining()];
+    buffer.get(array);
+    return new String(array, Charset.forName("UTF-8"));
+  }
 }
diff --git a/src/main/java/com/intel/jndn/management/helpers/FetchHelper.java b/src/main/java/com/intel/jndn/management/helpers/FetchHelper.java
new file mode 100644
index 0000000..94e6863
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/helpers/FetchHelper.java
@@ -0,0 +1,195 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.helpers;
+
+import net.named_data.jndn.*;
+import net.named_data.jndn.encoding.EncodingException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class FetchHelper implements OnData, OnTimeout {
+  public static final long DEFAULT_TIMEOUT = 2000;
+
+  private static final Logger LOG = Logger.getLogger(FetchHelper.class.getName());
+
+  private State state;
+  private Face face;
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Prevent creation of FetchHelper instances: use getData or getSegmentedData
+   */
+  private FetchHelper()
+  {
+  }
+
+  /**
+   * Private constructor: use getData or getSegmentedData
+   */
+  private FetchHelper(Face face)
+  {
+    this.face = face;
+  }
+
+  /**
+   * Get a single Data packet
+   * @param face Face instance
+   * @param interest Interest to retrieve Data
+   * @return Data packet
+   * @throws IOException if failed to retrieve packet, e.g., timeout occured
+   */
+  public static Data
+  getData(Face face, Interest interest) throws IOException {
+    FetchHelper fetcher = new FetchHelper(face);
+    return fetcher.getData(interest);
+  }
+
+  /**
+   * Get data using the exact name (without implicit digest)
+   * @param face Face instance
+   * @param name Exact name of the data packet to retrieve
+   *
+   * TODO: Allow authentication of retrieved data packets
+   */
+  public static Data
+  getData(Face face, Name name) throws IOException {
+    FetchHelper fetcher = new FetchHelper(face);
+
+    Interest interest = new Interest(name);
+    interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
+    interest.setMustBeFresh(false); // this is bug in jndn
+    // interest.setMinSuffixComponents(1); // implicit digest
+    // interest.setMaxSuffixComponents(1); // implicit digest
+    return fetcher.getData(interest);
+  }
+
+  /**
+   * Get concatenated data from the segmented
+   * @param face Face instance
+   * @param prefix Prefix of the retrieved data. The retrieved data must have version and segment numbers after this
+   *               prefix
+   *
+   * Note that this method will first send interest with MustBeFresh selector to discover "latest" version of the
+   *               stream and then retrieve the rest of the stream
+   *
+   * TODO: Allow authentication of retrieved data packets
+   */
+  public static List<Data>
+  getSegmentedData(Face face, Name prefix) throws IOException {
+    FetchHelper fetcher = new FetchHelper(face);
+
+    Interest interest = new Interest(new Name(prefix));
+    interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
+    interest.setMustBeFresh(true);
+    interest.setChildSelector(Interest.CHILD_SELECTOR_RIGHT);
+    // interest.setMinSuffixComponents(3); // version, segment, implicit digest
+    // interest.setMaxSuffixComponents(3); // version, segment, implicit digest
+
+    Data data = fetcher.getData(interest);
+
+    try {
+      data.getName().get(-1).toSegment();
+    }
+    catch (EncodingException e) {
+      throw new IOException("Retrieved data does not have segment number as the last name component", e);
+    }
+    if (data.getName().size() != prefix.size() + 2) {
+      throw new IOException("Retrieved data is not part of segmented stream");
+    }
+
+    long finalBlockId = 0;
+    try {
+      finalBlockId = data.getMetaInfo().getFinalBlockId().toSegment();
+    }
+    catch (EncodingException e) {
+      throw new IOException("Requested segmented stream is unbounded", e);
+    }
+
+    List<Data> segments = new ArrayList<>();
+    segments.add(data);
+
+    prefix.append(data.getName().get(-2));
+    for (int i = 0; i < finalBlockId; i++) {
+      interest = new Interest(new Name(prefix).appendSegment(i));
+      interest.setInterestLifetimeMilliseconds(DEFAULT_TIMEOUT);
+      interest.setMustBeFresh(false);
+      // interest.setMinSuffixComponents(1); // implicit digest
+      // interest.setMaxSuffixComponents(1); // implicit digest
+      segments.add(fetcher.getData(interest));
+    }
+
+    return segments;
+  }
+
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  private Data getData(Interest interest) throws IOException {
+    this.state = new State();
+    this.face.expressInterest(interest, this, this);
+
+    while (!state.isDone) {
+      try {
+        face.processEvents();
+      } catch (EncodingException e) {
+        LOG.log(Level.INFO, "Decoding error: " + e.getMessage(), e);
+      }
+      try {
+        Thread.sleep(20);
+      } catch (InterruptedException e) {
+        // ok
+      }
+    }
+
+    if (state.response == null) {
+      throw new IOException("Communication with NFD failed");
+    }
+
+    return state.response;
+  }
+
+  @Override
+  public void onData(Interest interest, Data data) {
+    state.response = data;
+    state.isDone = true;
+  }
+
+  @Override
+  public void onTimeout(Interest interest) {
+    state.nRetries--;
+    if (state.nRetries > 0) {
+      try {
+        face.expressInterest(new Interest(interest).setNonce(null), this, this);
+      } catch (IOException e) {
+        LOG.log(Level.INFO, "Error while expressing interest: " + e.toString(), e);
+      }
+    }
+    else {
+      state.isDone = true;
+    }
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+
+  private static class State {
+    public int nRetries = 3;
+    public Data response = null;
+    public boolean isDone = false;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/helpers/StatusDatasetHelper.java b/src/main/java/com/intel/jndn/management/helpers/StatusDatasetHelper.java
new file mode 100644
index 0000000..0db8341
--- /dev/null
+++ b/src/main/java/com/intel/jndn/management/helpers/StatusDatasetHelper.java
@@ -0,0 +1,79 @@
+/*
+ * jndn-management
+ * Copyright (c) 2015-2016, 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.helpers;
+
+import com.intel.jndn.management.ManagementException;
+import com.intel.jndn.management.types.Decodable;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.named_data.jndn.Data;
+import net.named_data.jndn.encoding.EncodingException;
+import net.named_data.jndn.encoding.tlv.TlvDecoder;
+import net.named_data.jndn.util.Blob;
+
+/**
+ * Helper class to handle StatusDatasets, see
+ * <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
+ *
+ * @author Andrew Brown <andrew.brown@intel.com>
+ */
+public class StatusDatasetHelper {
+
+  /**
+   * Prevent instances of StatusDatasetHelper
+   */
+  private StatusDatasetHelper() {
+  }
+
+  public static ByteBuffer
+  combine(List<Data> segments) {
+    int size = 0;
+    for (Data segment : segments) {
+      size += segment.getContent().size();
+    }
+    ByteBuffer payloadBuffer = ByteBuffer.allocate(size);
+    for (Data segment : segments) {
+      payloadBuffer.put(segment.getContent().getImmutableArray());
+    }
+    payloadBuffer.flip();
+
+    return payloadBuffer;
+  }
+
+  /**
+   * Decode multiple status entries as part of a StatusDatasetHelper, see
+   * <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
+   */
+  public static final <T extends Decodable> List<T>
+  wireDecode(List<Data> segments, Class<T> type) throws ManagementException {
+    Blob payload = new Blob(combine(segments), false);
+
+    List<T> entries = new ArrayList<>();
+    int endOffset = payload.size();
+    TlvDecoder decoder = new TlvDecoder(payload.buf());
+    while (decoder.getOffset() < endOffset) {
+      try {
+        T entry = type.newInstance();
+        entry.wireDecode(decoder);
+        entries.add(entry);
+      } catch (IllegalAccessException|InstantiationException|EncodingException e) {
+        throw new ManagementException("Failed to read status dataset.", e);
+      }
+    }
+    return entries;
+  }
+}
diff --git a/src/main/java/com/intel/jndn/management/types/ControlResponse.java b/src/main/java/com/intel/jndn/management/types/ControlResponse.java
index 5514244..0d8404f 100644
--- a/src/main/java/com/intel/jndn/management/types/ControlResponse.java
+++ b/src/main/java/com/intel/jndn/management/types/ControlResponse.java
@@ -13,7 +13,7 @@
  */
 package com.intel.jndn.management.types;
 
-import com.intel.jndn.management.EncodingHelper;
+import com.intel.jndn.management.helpers.EncodingHelper;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
diff --git a/src/main/java/com/intel/jndn/management/types/Decodable.java b/src/main/java/com/intel/jndn/management/types/Decodable.java
index aec50dd..05797aa 100644
--- a/src/main/java/com/intel/jndn/management/types/Decodable.java
+++ b/src/main/java/com/intel/jndn/management/types/Decodable.java
@@ -17,12 +17,11 @@
 import net.named_data.jndn.encoding.tlv.TlvDecoder;
 
 /**
- * Interface used by StatusDataset to decode generic message types; if they are
- * Decodable, then StatusDataset will instantiate and decode them.
+ * Interface used by StatusDatasetHelper to decode generic message types; if they are
+ * Decodable, then StatusDatasetHelper will instantiate and decode them.
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public interface Decodable {
-
-  public void wireDecode(TlvDecoder decoder) throws EncodingException;
+  void wireDecode(TlvDecoder decoder) throws EncodingException;
 }
diff --git a/src/main/java/com/intel/jndn/management/types/FacePersistency.java b/src/main/java/com/intel/jndn/management/types/FacePersistency.java
deleted file mode 100644
index d294fcb..0000000
--- a/src/main/java/com/intel/jndn/management/types/FacePersistency.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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;
-
-/**
- * Indicate whether the face is persistent; used by FaceStatus. See
- * <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">http://redmine.named-data.net/projects/nfd/widi/FaceMgmt</a>
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public enum FacePersistency {
-
-  PERSISTENT(0),
-  ON_DEMAND(1),
-  PERMANENT(2);
-
-  FacePersistency(int value) {
-    value_ = value;
-  }
-
-  public final int getNumericValue() {
-    return value_;
-  }
-  private final int value_;
-}
diff --git a/src/main/java/com/intel/jndn/management/types/FaceScope.java b/src/main/java/com/intel/jndn/management/types/FaceScope.java
deleted file mode 100644
index bcba855..0000000
--- a/src/main/java/com/intel/jndn/management/types/FaceScope.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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;
-
-/**
- * Indicate whether the face is local for scope control purposes; used by
- * FaceStatus See
- * <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">http://redmine.named-data.net/projects/nfd/widi/FaceMgmt</a>
- *
- * @author andrew
- */
-public enum FaceScope {
-
-  LOCAL(0),
-  NON_LOCAL(1);
-
-  FaceScope(int value) {
-    value_ = value;
-  }
-
-  public final int getNumericValue() {
-    return value_;
-  }
-  private final int value_;
-}
diff --git a/src/main/java/com/intel/jndn/management/types/FaceStatus.java b/src/main/java/com/intel/jndn/management/types/FaceStatus.java
index 88dceaf..abceaca 100644
--- a/src/main/java/com/intel/jndn/management/types/FaceStatus.java
+++ b/src/main/java/com/intel/jndn/management/types/FaceStatus.java
@@ -14,44 +14,59 @@
 package com.intel.jndn.management.types;
 
 import java.nio.ByteBuffer;
+import com.intel.jndn.management.enums.NfdTlv;
+import com.intel.jndn.management.enums.FacePersistency;
+import com.intel.jndn.management.enums.FaceScope;
+import com.intel.jndn.management.enums.LinkType;
+import com.intel.jndn.management.helpers.EncodingHelper;
 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 FaceStatus object from /localhost/nfd/faces/list; see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt">http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt</a>
- * for details
+ * Represent a FaceStatus object from /localhost/nfd/faces/list
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt">Face Management</a>
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class FaceStatus implements Decodable {
+  private int faceId = 0;
+  private String remoteUri = "";
+  private String localUri = "";
+  private FaceScope faceScope = FaceScope.LOCAL;
+  private FacePersistency facePersistency = FacePersistency.PERSISTENT;
+  private LinkType linkType = LinkType.POINT_TO_POINT;
+
+  private int expirationPeriod = 0;
+  private int inInterests = 0;
+  private int inDatas = 0;
+  private int inNacks = 0;
+
+  private int outInterests = 0;
+  private int outDatas = 0;
+  private int outNacks = 0;
+
+  private int inBytes = 0;
+  private int outBytes = 0;
+
+  /////////////////////////////////////////////////////////////////////////////
 
   /**
-   * Spec from
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/ControlCommand">http://redmine.named-data.net/projects/nfd/wiki/ControlCommand</a>
+   * Default constructor
    */
-  public static final int TLV_FACE_ID = 105;
-  public static final int TLV_URI = 114;
-  public static final int TLV_EXPIRATION_PERIOD = 109;
+  public FaceStatus() {
+    // nothing to do
+  }
 
   /**
-   * Spec from
-   * <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">http://redmine.named-data.net/projects/nfd/widi/FaceMgmt</a>
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
    */
-  public static final int TLV_FACE_STATUS = 128;
-  public static final int TLV_LOCAL_URI = 129;
-  public static final int TLV_CHANNEL_STATUS = 130;
-  public static final int TLV_FACE_SCOPE = 132;
-  public static final int TLV_FACE_PERSISTENCY = 133;
-  public static final int TLV_LINK_TYPE = 134;
-  public static final int TLV_N_IN_INTERESTS = 144;
-  public static final int TLV_N_IN_DATAS = 145;
-  public static final int TLV_N_OUT_INTERESTS = 146;
-  public static final int TLV_N_OUT_DATAS = 147;
-  public static final int TLV_N_IN_BYTES = 148;
-  public static final int TLV_N_OUT_BYTES = 149;
+  public FaceStatus(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
 
   /**
    * Encode using a new TLV encoder.
@@ -65,33 +80,38 @@
   }
 
   /**
-   * Encode as part of an existing encode context.
-   *
-   * @param encoder
+   * Encode as part of an existing encode context
    */
   public final void wireEncode(TlvEncoder encoder) {
     int saveLength = encoder.getLength();
-    encoder.writeNonNegativeIntegerTlv(TLV_N_OUT_BYTES, outBytes);
-    encoder.writeNonNegativeIntegerTlv(TLV_N_IN_BYTES, inBytes);
-    encoder.writeNonNegativeIntegerTlv(TLV_N_OUT_DATAS, outDatas);
-    encoder.writeNonNegativeIntegerTlv(TLV_N_OUT_INTERESTS, outInterests);
-    encoder.writeNonNegativeIntegerTlv(TLV_N_IN_DATAS, inDatas);
-    encoder.writeNonNegativeIntegerTlv(TLV_N_IN_INTERESTS, inInterests);
-    encoder.writeNonNegativeIntegerTlv(TLV_LINK_TYPE, linkType.getNumericValue());
-    encoder.writeNonNegativeIntegerTlv(TLV_FACE_PERSISTENCY, facePersistency.getNumericValue());
-    encoder.writeNonNegativeIntegerTlv(TLV_FACE_SCOPE, faceScope.getNumericValue());
-    encoder.writeOptionalNonNegativeIntegerTlv(TLV_EXPIRATION_PERIOD, expirationPeriod);
-    encoder.writeBlobTlv(TLV_LOCAL_URI, new Blob(localUri).buf());
-    encoder.writeBlobTlv(TLV_URI, new Blob(uri).buf());
-    encoder.writeNonNegativeIntegerTlv(TLV_FACE_ID, faceId);
-    encoder.writeTypeAndLength(TLV_FACE_STATUS, encoder.getLength() - saveLength);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutBytes, outBytes);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInBytes, inBytes);
+
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutNacks, outNacks);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutDatas, outDatas);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutInterests, outInterests);
+
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInNacks, inNacks);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInDatas, inDatas);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInInterests, inInterests);
+
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.LinkType, linkType.toInteger());
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.FacePersistency, facePersistency.toInteger());
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.FaceScope, faceScope.toInteger());
+
+    encoder.writeOptionalNonNegativeIntegerTlv(NfdTlv.ExpirationPeriod, expirationPeriod);
+    encoder.writeBlobTlv(NfdTlv.LocalUri, new Blob(localUri).buf());
+    encoder.writeBlobTlv(NfdTlv.Uri, new Blob(remoteUri).buf());
+
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.FaceId, faceId);
+    encoder.writeTypeAndLength(NfdTlv.FaceStatus, encoder.getLength() - saveLength);
   }
 
   /**
    * 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.
+   *              limit(), but does not change the position.
    * @throws net.named_data.jndn.encoding.EncodingException
    */
   public final void wireDecode(ByteBuffer input) throws EncodingException {
@@ -100,37 +120,38 @@
   }
 
   /**
-   * Decode as part of an existing decode context.
-   *
-   * @param decoder
-   * @throws EncodingException
+   * Decode as part of an existing decode context
    */
   @Override
   public void wireDecode(TlvDecoder decoder) throws EncodingException {
-    int endOffset = decoder.readNestedTlvsStart(TLV_FACE_STATUS);
+    int endOffset = decoder.readNestedTlvsStart(NfdTlv.FaceStatus);
     // parse
-    this.faceId = (int) decoder.readNonNegativeIntegerTlv(TLV_FACE_ID);
-    Blob uri_ = new Blob(decoder.readBlobTlv(TLV_URI), true); // copy because buffer is immutable
-    this.uri = uri_.toString();
-    Blob localUri_ = new Blob(decoder.readBlobTlv(TLV_LOCAL_URI), true); // copy because buffer is immutable
-    this.localUri = localUri_.toString();
-    this.expirationPeriod = (int) decoder.readOptionalNonNegativeIntegerTlv(TLV_EXPIRATION_PERIOD, endOffset);
-    this.faceScope = FaceScope.values()[(int) decoder.readNonNegativeIntegerTlv(TLV_FACE_SCOPE)];
-    this.facePersistency = FacePersistency.values()[(int) decoder.readNonNegativeIntegerTlv(TLV_FACE_PERSISTENCY)];
-    this.linkType = LinkType.values()[(int) decoder.readNonNegativeIntegerTlv(TLV_LINK_TYPE)];
-    this.inInterests = (int) decoder.readNonNegativeIntegerTlv(TLV_N_IN_INTERESTS);
-    this.inDatas = (int) decoder.readNonNegativeIntegerTlv(TLV_N_IN_DATAS);
-    this.outInterests = (int) decoder.readNonNegativeIntegerTlv(TLV_N_OUT_INTERESTS);
-    this.outDatas = (int) decoder.readNonNegativeIntegerTlv(TLV_N_OUT_DATAS);
-    this.inBytes = (int) decoder.readNonNegativeIntegerTlv(TLV_N_IN_BYTES);
-    this.outBytes = (int) decoder.readNonNegativeIntegerTlv(TLV_N_OUT_BYTES);
+    this.faceId = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.FaceId);
+
+    this.remoteUri = EncodingHelper.toString(decoder.readBlobTlv(NfdTlv.Uri));
+    this.localUri = EncodingHelper.toString(decoder.readBlobTlv(NfdTlv.LocalUri));
+
+    this.expirationPeriod = (int) decoder.readOptionalNonNegativeIntegerTlv(NfdTlv.ExpirationPeriod, endOffset);
+    this.faceScope = FaceScope.fromInteger((int) decoder.readNonNegativeIntegerTlv(NfdTlv.FaceScope));
+    this.facePersistency = FacePersistency.fromInteger((int) decoder.readNonNegativeIntegerTlv(NfdTlv.FacePersistency));
+    this.linkType = LinkType.fromInteger((int) decoder.readNonNegativeIntegerTlv(NfdTlv.LinkType));
+
+    this.inInterests = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NInInterests);
+    this.inDatas = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NInDatas);
+    this.inNacks = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NInNacks);
+
+    this.outInterests = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NOutInterests);
+    this.outDatas = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NOutDatas);
+    this.outNacks = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NOutNacks);
+
+    this.inBytes = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NInBytes);
+    this.outBytes = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.NOutBytes);
+
     decoder.finishNestedTlvs(endOffset);
   }
 
   /**
    * Get face ID
-   *
-   * @return
    */
   public int getFaceId() {
     return faceId;
@@ -138,35 +159,29 @@
 
   /**
    * Set face ID
-   *
-   * @param faceId
    */
-  public void setFaceId(int faceId) {
+  public FaceStatus setFaceId(int faceId) {
     this.faceId = faceId;
+    return this;
   }
 
   /**
    * Get face ID
-   *
-   * @return
    */
-  public String getUri() {
-    return uri;
+  public String getRemoteUri() {
+    return remoteUri;
   }
 
   /**
    * Set URI
-   *
-   * @param uri
    */
-  public void setUri(String uri) {
-    this.uri = uri;
+  public FaceStatus setRemoteUri(String uri) {
+    this.remoteUri = uri;
+    return this;
   }
 
   /**
    * Get face ID
-   *
-   * @return
    */
   public String getLocalUri() {
     return localUri;
@@ -174,17 +189,21 @@
 
   /**
    * Set local URI
-   *
-   * @param localUri
    */
-  public void setLocalUri(String localUri) {
+  public FaceStatus setLocalUri(String localUri) {
     this.localUri = localUri;
+    return this;
+  }
+
+  /**
+   * Check if Face has expiration period set
+   */
+  public boolean hasExpirationPeriod() {
+    return expirationPeriod > 0;
   }
 
   /**
    * Get expiration period
-   *
-   * @return
    */
   public int getExpirationPeriod() {
     return expirationPeriod;
@@ -192,17 +211,14 @@
 
   /**
    * Set expiration period
-   *
-   * @param expirationPeriod
    */
-  public void setExpirationPeriod(int expirationPeriod) {
+  public FaceStatus setExpirationPeriod(int expirationPeriod) {
     this.expirationPeriod = expirationPeriod;
+    return this;
   }
 
   /**
    * Get face scope value
-   *
-   * @return
    */
   public FaceScope getFaceScope() {
     return faceScope;
@@ -210,17 +226,14 @@
 
   /**
    * Set face scope value
-   *
-   * @param faceScope
    */
-  public void setFaceScope(FaceScope faceScope) {
+  public FaceStatus setFaceScope(FaceScope faceScope) {
     this.faceScope = faceScope;
+    return this;
   }
 
   /**
    * Get face persistency value
-   *
-   * @return
    */
   public FacePersistency getFacePersistency() {
     return facePersistency;
@@ -228,17 +241,14 @@
 
   /**
    * Set face persistency value
-   *
-   * @param facePersistency
    */
-  public void setFacePersistency(FacePersistency facePersistency) {
+  public FaceStatus setFacePersistency(FacePersistency facePersistency) {
     this.facePersistency = facePersistency;
+    return this;
   }
 
   /**
    * Get link type
-   *
-   * @return
    */
   public LinkType getLinkType() {
     return linkType;
@@ -246,132 +256,130 @@
 
   /**
    * Set link type
-   *
-   * @param linkType
    */
-  public void setLinkType(LinkType linkType) {
+  public FaceStatus setLinkType(LinkType linkType) {
     this.linkType = linkType;
+    return this;
   }
 
   /**
    * Get number of received Interest packets
-   *
-   * @return
    */
-  public int getInInterests() {
+  public int getNInInterests() {
     return inInterests;
   }
 
   /**
    * Set number of received Interest packets
-   *
-   * @param inInterests
    */
-  public void setInInterests(int inInterests) {
+  public FaceStatus setNInInterests(int inInterests) {
     this.inInterests = inInterests;
+    return this;
   }
 
   /**
    * Get number of sent Interest packets
-   *
-   * @return
    */
-  public int getOutInterests() {
+  public int getNOutInterests() {
     return outInterests;
   }
 
   /**
    * Set number of sent Interest packets
-   *
-   * @param outInterests
    */
-  public void setOutInterests(int outInterests) {
+  public FaceStatus setNOutInterests(int outInterests) {
     this.outInterests = outInterests;
+    return this;
   }
 
   /**
    * Get number of received Data packets
-   *
-   * @return
    */
-  public int getInDatas() {
+  public int getNInDatas() {
     return inDatas;
   }
 
   /**
    * Set number of received Data packets
-   *
-   * @param inDatas
    */
-  public void setInDatas(int inDatas) {
+  public FaceStatus setNInDatas(int inDatas) {
     this.inDatas = inDatas;
+    return this;
   }
 
   /**
    * Get number of sent Data packets
-   *
-   * @return
    */
-  public int getOutDatas() {
+  public int getNOutDatas() {
     return outDatas;
   }
 
   /**
    * Set number of sent Data packets
-   *
-   * @param outDatas
    */
-  public void setOutDatas(int outDatas) {
+  public FaceStatus setNOutDatas(int outDatas) {
     this.outDatas = outDatas;
+    return this;
   }
 
   /**
-   * Get number of input bytes
-   *
-   * @return
+   * Get number of received Data packets
    */
-  public int getInBytes() {
+  public int getNInNacks() {
+    return inNacks;
+  }
+
+  /**
+   * Set number of received Data packets
+   */
+  public FaceStatus setNInNacks(int inNacks) {
+    this.inNacks = inNacks;
+    return this;
+  }
+
+  /**
+   * Get number of sent Data packets
+   */
+  public int getNOutNacks() {
+    return outNacks;
+  }
+
+  /**
+   * Set number of sent Data packets
+   */
+  public FaceStatus setNOutNacks(int outNacks) {
+    this.outNacks = outNacks;
+    return this;
+  }
+
+
+  /**
+   * Get number of input bytes
+   */
+  public int getNInBytes() {
     return inBytes;
   }
 
   /**
    * Set number of input bytes
-   *
-   * @param inBytes
    */
-  public void setInBytes(int inBytes) {
+  public FaceStatus setNInBytes(int inBytes) {
     this.inBytes = inBytes;
+    return this;
   }
 
   /**
    * Get number of output bytes
-   *
-   * @return
    */
-  public int getOutBytes() {
+  public int getNOutBytes() {
     return outBytes;
   }
 
   /**
    * Set number of output bytes
-   *
-   * @param outBytes
    */
-  public void setOutBytes(int outBytes) {
+  public FaceStatus setNOutBytes(int outBytes) {
     this.outBytes = outBytes;
+    return this;
   }
-
-  private int faceId = -1;
-  private String uri = ""; // can't use URI because some are invalid syntax
-  private String localUri = ""; // can't use URI because some are invalid syntax
-  private int expirationPeriod = 0;
-  private FaceScope faceScope = FaceScope.LOCAL;
-  private FacePersistency facePersistency = FacePersistency.ON_DEMAND;
-  private LinkType linkType = LinkType.POINT_TO_POINT;
-  private int inInterests = 0;
-  private int outInterests = 0;
-  private int inDatas = 0;
-  private int outDatas = 0;
-  private int inBytes = 0;
-  private int outBytes = 0;
 }
diff --git a/src/main/java/com/intel/jndn/management/types/FibEntry.java b/src/main/java/com/intel/jndn/management/types/FibEntry.java
index 8c74636..e30e9a9 100644
--- a/src/main/java/com/intel/jndn/management/types/FibEntry.java
+++ b/src/main/java/com/intel/jndn/management/types/FibEntry.java
@@ -13,10 +13,13 @@
  */
 package com.intel.jndn.management.types;
 
-import com.intel.jndn.management.EncodingHelper;
+import com.intel.jndn.management.helpers.EncodingHelper;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.ListIterator;
+
+import com.intel.jndn.management.enums.NfdTlv;
 import net.named_data.jndn.Name;
 import net.named_data.jndn.encoding.EncodingException;
 import net.named_data.jndn.encoding.tlv.TlvDecoder;
@@ -24,14 +27,32 @@
 import net.named_data.jndn.util.Blob;
 
 /**
- * Represent a FibEntry returned from /localhost/nfd/fib/list; see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset">http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset</a>
+ * Represent a FibEntry returned from /localhost/nfd/fib/list
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset">FIB Dataset</a>
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class FibEntry implements Decodable {
+  private Name name = new Name();
+  private List<NextHopRecord> records = new ArrayList<>();
 
-  public final static int TLV_FIB_ENTRY = 128;
+  /////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Default constructor
+   */
+  public FibEntry() {
+    // nothing to do
+  }
+
+  /**
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
+   */
+  public FibEntry(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
 
   /**
    * Encode using a new TLV encoder.
@@ -45,24 +66,23 @@
   }
 
   /**
-   * Encode as part of an existing encode context.
-   *
-   * @param encoder
+   * Encode as part of an existing encode context
    */
   public final void wireEncode(TlvEncoder encoder) {
     int saveLength = encoder.getLength();
-    for (NextHopRecord record : records) {
-      record.wireEncode(encoder);
+    ListIterator<NextHopRecord> nh = records.listIterator(records.size());
+    while (nh.hasPrevious()) {
+      nh.previous().wireEncode(encoder);
     }
     EncodingHelper.encodeName(name, encoder);
-    encoder.writeTypeAndLength(TLV_FIB_ENTRY, encoder.getLength() - saveLength);
+    encoder.writeTypeAndLength(NfdTlv.FibEntry, encoder.getLength() - saveLength);
   }
 
   /**
    * 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.
+   *              limit(), but does not change the position.
    * @throws EncodingException For invalid encoding.
    */
   public final void wireDecode(ByteBuffer input) throws EncodingException {
@@ -71,14 +91,11 @@
   }
 
   /**
-   * Decode as part of an existing decode context.
-   *
-   * @param decoder
-   * @throws EncodingException
+   * Decode as part of an existing decode context
    */
   @Override
   public final void wireDecode(TlvDecoder decoder) throws EncodingException {
-    int endOffset = decoder.readNestedTlvsStart(TLV_FIB_ENTRY);
+    int endOffset = decoder.readNestedTlvsStart(NfdTlv.FibEntry);
     name = EncodingHelper.decodeName(decoder);
     while (decoder.getOffset() < endOffset) {
       NextHopRecord record = new NextHopRecord();
@@ -90,40 +107,36 @@
 
   /**
    * Get name
-   *
-   * @return
    */
-  public Name getName() {
+  public Name getPrefix() {
     return name;
   }
 
   /**
    * Set name
-   *
-   * @param name
    */
-  public void setName(Name name) {
+  public FibEntry setPrefix(Name name) {
     this.name = name;
+    return this;
   }
 
   /**
    * Get records
-   *
-   * @return
    */
-  public List<NextHopRecord> getRecords() {
+  public List<NextHopRecord> getNextHopRecords() {
     return records;
   }
 
   /**
    * Set records
-   *
-   * @param records
    */
-  public void setRecords(List<NextHopRecord> records) {
+  public FibEntry setNextHopRecords(List<NextHopRecord> records) {
     this.records = records;
+    return this;
   }
 
-  private Name name = new Name();
-  private List<NextHopRecord> records = new ArrayList<>();
+  public FibEntry addNextHopRecord(NextHopRecord record) {
+    this.records.add(record);
+    return this;
+  }
 }
diff --git a/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java b/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java
index 88ecc35..7ad4712 100644
--- a/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java
+++ b/src/main/java/com/intel/jndn/management/types/ForwarderStatus.java
@@ -14,31 +14,52 @@
 package com.intel.jndn.management.types;
 
 import java.nio.ByteBuffer;
+
+import com.intel.jndn.management.enums.NfdTlv;
 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.
+ * Represent a ForwarderStatus object
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus">ForwarderStatus</a>
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class ForwarderStatus implements Decodable {
+  private String nfdVersion = "";
+  private long startTimestamp = 0;
+  private long currentTimestamp = 0;
+  private long nNameTreeEntries = 0;
+  private long nFibEntries = 0;
+  private long nPitEntries = 0;
+  private long nMeasurementEntries = 0;
+  private long nCsEntries = 0;
+  private long nInInterests = 0;
+  private long nInDatas = 0;
+  private long nInNacks = 0;
+  private long nOutInterests = 0;
+  private long nOutDatas = 0;
+  private long nOutNacks = 0;
 
-  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;
+  /////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Default constructor
+   */
+  public ForwarderStatus() {
+    // nothing to do
+  }
+
+  /**
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
+   */
+  public ForwarderStatus(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
 
   /**
    * Encode using a new TLV encoder.
@@ -53,22 +74,22 @@
 
   /**
    * 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());
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutNacks, nOutNacks);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutDatas, nOutDatas);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NOutInterests, nOutInterests);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInNacks, nInNacks);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInDatas, nInDatas);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NInInterests, nInInterests);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NCsEntries, nCsEntries);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NMeasurementsEntries, nMeasurementEntries);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NPitEntries, nPitEntries);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NFibEntries, nFibEntries);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.NNameTreeEntries, nNameTreeEntries);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.CurrentTimestamp, currentTimestamp);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.StartTimestamp, startTimestamp);
+    encoder.writeBlobTlv(NfdTlv.NfdVersion, new Blob(nfdVersion).buf());
   }
 
   /**
@@ -84,25 +105,24 @@
   }
 
   /**
-   * Decode as part of an existing decode context.
-   *
-   * @param decoder
-   * @throws EncodingException
+   * Decode as part of an existing decode context
    */
   @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);
+    this.nfdVersion = new Blob(decoder.readBlobTlv(NfdTlv.NfdVersion), true).toString();
+    this.startTimestamp = decoder.readNonNegativeIntegerTlv(NfdTlv.StartTimestamp);
+    this.currentTimestamp = decoder.readNonNegativeIntegerTlv(NfdTlv.CurrentTimestamp);
+    this.nNameTreeEntries = decoder.readNonNegativeIntegerTlv(NfdTlv.NNameTreeEntries);
+    this.nFibEntries = decoder.readNonNegativeIntegerTlv(NfdTlv.NFibEntries);
+    this.nPitEntries = decoder.readNonNegativeIntegerTlv(NfdTlv.NPitEntries);
+    this.nMeasurementEntries = decoder.readNonNegativeIntegerTlv(NfdTlv.NMeasurementsEntries);
+    this.nCsEntries = decoder.readNonNegativeIntegerTlv(NfdTlv.NCsEntries);
+    this.nInInterests = decoder.readNonNegativeIntegerTlv(NfdTlv.NInInterests);
+    this.nInDatas = decoder.readNonNegativeIntegerTlv(NfdTlv.NInDatas);
+    this.nInNacks = decoder.readNonNegativeIntegerTlv(NfdTlv.NInNacks);
+    this.nOutInterests = decoder.readNonNegativeIntegerTlv(NfdTlv.NOutInterests);
+    this.nOutDatas = decoder.readNonNegativeIntegerTlv(NfdTlv.NOutDatas);
+    this.nOutNacks = decoder.readNonNegativeIntegerTlv(NfdTlv.NOutNacks);
   }
 
   public String getNfdVersion() {
@@ -129,88 +149,91 @@
     this.currentTimestamp = currentTimestamp;
   }
 
-  public long getNumNameTreeEntries() {
-    return numNameTreeEntries;
+  public long getNNameTreeEntries() {
+    return nNameTreeEntries;
   }
 
-  public void setNumNameTreeEntries(long numNameTreeEntries) {
-    this.numNameTreeEntries = numNameTreeEntries;
+  public void setNNameTreeEntries(long nNameTreeEntries) {
+    this.nNameTreeEntries = nNameTreeEntries;
   }
 
-  public long getNumFibEntries() {
-    return numFibEntries;
+  public long getNFibEntries() {
+    return nFibEntries;
   }
 
-  public void setNumFibEntries(long numFibEntries) {
-    this.numFibEntries = numFibEntries;
+  public void setNFibEntries(long nFibEntries) {
+    this.nFibEntries = nFibEntries;
   }
 
-  public long getNumPitEntries() {
-    return numPitEntries;
+  public long getNPitEntries() {
+    return nPitEntries;
   }
 
-  public void setNumPitEntries(long numPitEntries) {
-    this.numPitEntries = numPitEntries;
+  public void setNPitEntries(long nPitEntries) {
+    this.nPitEntries = nPitEntries;
   }
 
-  public long getNumMeasurementEntries() {
-    return numMeasurementEntries;
+  public long getNMeasurementsEntries() {
+    return nMeasurementEntries;
   }
 
-  public void setNumMeasurementEntries(long numMeasurementEntries) {
-    this.numMeasurementEntries = numMeasurementEntries;
+  public void setNMeasurementsEntries(long nMeasurementEntries) {
+    this.nMeasurementEntries = nMeasurementEntries;
   }
 
-  public long getNumCsEntries() {
-    return numCsEntries;
+  public long getNCsEntries() {
+    return nCsEntries;
   }
 
-  public void setNumCsEntries(long numCsEntries) {
-    this.numCsEntries = numCsEntries;
+  public void setNCsEntries(long nCsEntries) {
+    this.nCsEntries = nCsEntries;
   }
 
-  public long getNumInInterests() {
-    return numInInterests;
+  public long getNInInterests() {
+    return nInInterests;
   }
 
-  public void setNumInInterests(long numInInterests) {
-    this.numInInterests = numInInterests;
+  public void setNInInterests(long nInInterests) {
+    this.nInInterests = nInInterests;
   }
 
-  public long getNumInDatas() {
-    return numInDatas;
+  public long getNInDatas() {
+    return nInDatas;
   }
 
-  public void setNumInDatas(long numInDatas) {
-    this.numInDatas = numInDatas;
+  public void setNInDatas(long nInDatas) {
+    this.nInDatas = nInDatas;
   }
 
-  public long getNumOutInterests() {
-    return numOutInterests;
+  public long getNOutInterests() {
+    return nOutInterests;
   }
 
-  public void setNumOutInterests(long numOutInterests) {
-    this.numOutInterests = numOutInterests;
+  public void setNOutInterests(long nOutInterests) {
+    this.nOutInterests = nOutInterests;
   }
 
-  public long getNumOutDatas() {
-    return numOutDatas;
+  public long getNOutDatas() {
+    return nOutDatas;
   }
 
-  public void setNumOutDatas(long numOutDatas) {
-    this.numOutDatas = numOutDatas;
+  public void setNOutDatas(long nOutDatas) {
+    this.nOutDatas = nOutDatas;
   }
 
-  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;
+  public long getNInNacks() {
+    return nInNacks;
+  }
+
+  public void setNInNacks(long nInNacks) {
+    this.nInNacks = nInNacks;
+  }
+
+  public long getNOutNacks() {
+    return nOutNacks;
+  }
+
+  public void setNOutNacks(long nOutNacks) {
+    this.nOutNacks = nOutNacks;
+  }
 }
diff --git a/src/main/java/com/intel/jndn/management/types/LinkType.java b/src/main/java/com/intel/jndn/management/types/LinkType.java
deleted file mode 100644
index a0f517c..0000000
--- a/src/main/java/com/intel/jndn/management/types/LinkType.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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;
-
-/**
- * Indicate the type of communication link; used by FaceStatus See
- * <a href="http://redmine.named-data.net/projects/nfd/widi/FaceMgmt">http://redmine.named-data.net/projects/nfd/widi/FaceMgmt</a>
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public enum LinkType {
-
-  POINT_TO_POINT(0),
-  MULTI_ACCESS(1);
-
-  LinkType(int value) {
-    value_ = value;
-  }
-
-  public final int getNumericValue() {
-    return value_;
-  }
-  private final int value_;
-}
diff --git a/src/main/java/com/intel/jndn/management/types/NextHopRecord.java b/src/main/java/com/intel/jndn/management/types/NextHopRecord.java
index 3b40104..84756e5 100644
--- a/src/main/java/com/intel/jndn/management/types/NextHopRecord.java
+++ b/src/main/java/com/intel/jndn/management/types/NextHopRecord.java
@@ -14,6 +14,8 @@
 package com.intel.jndn.management.types;
 
 import java.nio.ByteBuffer;
+
+import com.intel.jndn.management.enums.NfdTlv;
 import net.named_data.jndn.encoding.EncodingException;
 import net.named_data.jndn.encoding.tlv.Tlv;
 import net.named_data.jndn.encoding.tlv.TlvDecoder;
@@ -21,19 +23,37 @@
 import net.named_data.jndn.util.Blob;
 
 /**
- * Represent a NextHopRecord in a FibEntry; see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset">http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset</a>
+ * Represent a NextHopRecord in a FibEntry
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/FibMgmt#FIB-Dataset">FIB Dataset</a>
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class NextHopRecord {
+  private int faceId;
+  private int cost;
 
-  public final static int TLV_NEXT_HOP_RECORD = 129;
+  /////////////////////////////////////////////////////////////////////////////
 
   /**
-   * Encode using a new TLV encoder.
+   * Default constructor
+   */
+  public NextHopRecord() {
+    // nothing to do
+  }
+
+  /**
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
+   */
+  public NextHopRecord(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
+
+  /**
+   * Encode using a new TLV encoder
    *
-   * @return The encoded buffer.
+   * @return The encoded buffer
    */
   public final Blob wireEncode() {
     TlvEncoder encoder = new TlvEncoder();
@@ -42,15 +62,13 @@
   }
 
   /**
-   * Encode as part of an existing encode context.
-   *
-   * @param encoder
+   * Encode as part of an existing encode context
    */
   public final void wireEncode(TlvEncoder encoder) {
     int saveLength = encoder.getLength();
     encoder.writeNonNegativeIntegerTlv(Tlv.ControlParameters_Cost, cost);
     encoder.writeNonNegativeIntegerTlv(Tlv.ControlParameters_FaceId, faceId);
-    encoder.writeTypeAndLength(TLV_NEXT_HOP_RECORD, encoder.getLength() - saveLength);
+    encoder.writeTypeAndLength(NfdTlv.NextHopRecord, encoder.getLength() - saveLength);
   }
 
   /**
@@ -66,13 +84,10 @@
   }
 
   /**
-   * Decode as part of an existing decode context.
-   *
-   * @param decoder
-   * @throws EncodingException
+   * Decode as part of an existing decode context
    */
   public final void wireDecode(TlvDecoder decoder) throws EncodingException {
-    int endOffset = decoder.readNestedTlvsStart(TLV_NEXT_HOP_RECORD);
+    int endOffset = decoder.readNestedTlvsStart(NfdTlv.NextHopRecord);
     this.faceId = (int) decoder.readNonNegativeIntegerTlv(Tlv.ControlParameters_FaceId);
     this.cost = (int) decoder.readNonNegativeIntegerTlv(Tlv.ControlParameters_Cost);
     decoder.finishNestedTlvs(endOffset);
@@ -80,8 +95,6 @@
 
   /**
    * Get face ID
-   *
-   * @return
    */
   public int getFaceId() {
     return faceId;
@@ -89,8 +102,6 @@
 
   /**
    * Set face ID
-   *
-   * @param faceId
    */
   public void setFaceId(int faceId) {
     this.faceId = faceId;
@@ -98,8 +109,6 @@
 
   /**
    * Get cost
-   *
-   * @return
    */
   public int getCost() {
     return cost;
@@ -107,13 +116,8 @@
 
   /**
    * Set cost
-   *
-   * @param cost
    */
   public void setCost(int cost) {
     this.cost = cost;
   }
-
-  private int faceId;
-  private int cost;
 }
diff --git a/src/main/java/com/intel/jndn/management/types/RibEntry.java b/src/main/java/com/intel/jndn/management/types/RibEntry.java
index 705352c..a5c0380 100644
--- a/src/main/java/com/intel/jndn/management/types/RibEntry.java
+++ b/src/main/java/com/intel/jndn/management/types/RibEntry.java
@@ -13,10 +13,13 @@
  */
 package com.intel.jndn.management.types;
 
-import com.intel.jndn.management.EncodingHelper;
+import com.intel.jndn.management.enums.NfdTlv;
+import com.intel.jndn.management.helpers.EncodingHelper;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.ListIterator;
+
 import net.named_data.jndn.Name;
 import net.named_data.jndn.encoding.EncodingException;
 import net.named_data.jndn.encoding.tlv.TlvDecoder;
@@ -24,19 +27,30 @@
 import net.named_data.jndn.util.Blob;
 
 /**
- * Represent a entry in the RIB; see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset</a>
- * for details
+ * Represent a entry in the RIB
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset">RIB Dataset</a>
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class RibEntry implements Decodable {
+  private Name name = new Name();
+  private List<Route> routes = new ArrayList<>();
 
   /**
-   * TLV type, see
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#TLV-TYPE-assignments">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#TLV-TYPE-assignments</a>
+   * Default constructor
    */
-  public final static int TLV_RIB_ENTRY = 128;
+  public RibEntry() {
+    // nothing to do
+  }
+
+  /**
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
+   */
+  public RibEntry(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
 
   /**
    * Encode using a new TLV encoder.
@@ -51,16 +65,15 @@
 
   /**
    * Encode as part of an existing encode context.
-   *
-   * @param encoder
    */
   public final void wireEncode(TlvEncoder encoder) {
     int saveLength = encoder.getLength();
-    for (Route route : routes) {
-      route.wireEncode(encoder);
+    ListIterator<Route> route = routes.listIterator(routes.size());
+    while (route.hasPrevious()) {
+      route.previous().wireEncode(encoder);
     }
     EncodingHelper.encodeName(name, encoder);
-    encoder.writeTypeAndLength(TLV_RIB_ENTRY, encoder.getLength() - saveLength);
+    encoder.writeTypeAndLength(NfdTlv.RibEntry, encoder.getLength() - saveLength);
   }
 
   /**
@@ -77,13 +90,10 @@
 
   /**
    * Decode as part of an existing decode context.
-   *
-   * @param decoder
-   * @throws EncodingException
    */
   @Override
   public final void wireDecode(TlvDecoder decoder) throws EncodingException {
-    int endOffset = decoder.readNestedTlvsStart(TLV_RIB_ENTRY);
+    int endOffset = decoder.readNestedTlvsStart(NfdTlv.RibEntry);
     name = EncodingHelper.decodeName(decoder);
     while (decoder.getOffset() < endOffset) {
       Route route = new Route();
@@ -95,8 +105,6 @@
 
   /**
    * Get name
-   *
-   * @return
    */
   public Name getName() {
     return name;
@@ -104,8 +112,6 @@
 
   /**
    * Set name
-   *
-   * @param name
    */
   public void setName(Name name) {
     this.name = name;
@@ -113,22 +119,46 @@
 
   /**
    * Get routes
-   *
-   * @return
    */
   public List<Route> getRoutes() {
     return routes;
   }
 
   /**
+   * Add route
+   */
+  public RibEntry addRoute(Route route) {
+    getRoutes().add(route);
+    return this;
+  }
+
+  /**
+   * Clear all routes
+   */
+  public void clearRoutes() {
+    getRoutes().clear();
+  }
+
+  /**
    * Set routes
-   *
-   * @param routes
    */
   public void setRoutes(List<Route> routes) {
     this.routes = routes;
   }
 
-  private Name name = new Name();
-  private List<Route> routes = new ArrayList<>();
+  /**
+   * Get human-readable representation of RibEntry
+   */
+  @Override
+  public String toString() {
+    StringBuilder out = new StringBuilder();
+    out.append("RibEntry{\n");
+    out.append("  Name: ").append(getName().toUri()).append("\n");
+
+    for (Route route : getRoutes()) {
+      out.append("  ").append(route.toString()).append("\n");
+    }
+    out.append("}");
+    return out.toString();
+  }
 }
diff --git a/src/main/java/com/intel/jndn/management/types/Route.java b/src/main/java/com/intel/jndn/management/types/Route.java
index 15c2050..0b9acb4 100644
--- a/src/main/java/com/intel/jndn/management/types/Route.java
+++ b/src/main/java/com/intel/jndn/management/types/Route.java
@@ -13,28 +13,47 @@
  */
 package com.intel.jndn.management.types;
 
-import net.named_data.jndn.encoding.tlv.Tlv;
 import java.nio.ByteBuffer;
-import net.named_data.jndn.ForwardingFlags;
+
+import com.intel.jndn.management.enums.NfdTlv;
+import com.intel.jndn.management.enums.RouteFlags;
 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 Route object from /localhost/nfd/rib/list; see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset</a>
- * for details.
+ * Represent a Route object from /localhost/nfd/rib/list
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#RIB-Dataset">RIB Dataset</a>
  *
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class Route {
+  public static final int INFINITE_EXPIRATION_PERIOD = -1;
+
+  private int faceId = -1;
+  private int origin = -1;
+  private int cost = -1;
+  private int flags = RouteFlags.CHILD_INHERIT.toInteger();
+  private int expirationPeriod = INFINITE_EXPIRATION_PERIOD;
+
+  /////////////////////////////////////////////////////////////////////////////
 
   /**
-   * TLV type, see
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#TLV-TYPE-assignments">http://redmine.named-data.net/projects/nfd/wiki/RibMgmt#TLV-TYPE-assignments</a>
+   * Default constructor
    */
-  public final static int TLV_ROUTE = 129;
+  public Route() {
+    // nothing to do
+  }
+
+  /**
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
+   */
+  public Route(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
 
   /**
    * Encode using a new TLV encoder.
@@ -54,19 +73,19 @@
    */
   public final void wireEncode(TlvEncoder encoder) {
     int saveLength = encoder.getLength();
-    encoder.writeOptionalNonNegativeIntegerTlv(Tlv.ControlParameters_ExpirationPeriod, faceId);
-    encoder.writeNonNegativeIntegerTlv(Tlv.ControlParameters_Flags, flags.getNfdForwardingFlags());
-    encoder.writeNonNegativeIntegerTlv(Tlv.ControlParameters_Cost, cost);
-    encoder.writeNonNegativeIntegerTlv(Tlv.ControlParameters_Origin, origin);
-    encoder.writeNonNegativeIntegerTlv(Tlv.ControlParameters_FaceId, faceId);
-    encoder.writeTypeAndLength(TLV_ROUTE, encoder.getLength() - saveLength);
+    encoder.writeOptionalNonNegativeIntegerTlv(NfdTlv.ExpirationPeriod, expirationPeriod);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.Flags, flags);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.Cost, cost);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.Origin, origin);
+    encoder.writeNonNegativeIntegerTlv(NfdTlv.FaceId, faceId);
+    encoder.writeTypeAndLength(NfdTlv.Route, encoder.getLength() - saveLength);
   }
 
   /**
    * 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.
+   *              limit(), but does not change the position.
    * @throws net.named_data.jndn.encoding.EncodingException
    */
   public final void wireDecode(ByteBuffer input) throws EncodingException {
@@ -81,19 +100,17 @@
    * @throws EncodingException
    */
   public final void wireDecode(TlvDecoder decoder) throws EncodingException {
-    int endOffset = decoder.readNestedTlvsStart(TLV_ROUTE);
-    this.faceId = (int) decoder.readNonNegativeIntegerTlv(Tlv.ControlParameters_FaceId);
-    this.origin = (int) decoder.readNonNegativeIntegerTlv(Tlv.ControlParameters_Origin);
-    this.cost = (int) decoder.readNonNegativeIntegerTlv(Tlv.ControlParameters_Cost);
-    this.flags.setNfdForwardingFlags((int) decoder.readNonNegativeIntegerTlv(Tlv.ControlParameters_Flags));
-    this.expirationPeriod = (int) decoder.readOptionalNonNegativeIntegerTlv(Tlv.ControlParameters_ExpirationPeriod, endOffset);
+    int endOffset = decoder.readNestedTlvsStart(NfdTlv.Route);
+    this.faceId = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.FaceId);
+    this.origin = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.Origin);
+    this.cost = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.Cost);
+    this.flags = (int) decoder.readNonNegativeIntegerTlv(NfdTlv.Flags);
+    this.expirationPeriod = (int) decoder.readOptionalNonNegativeIntegerTlv(NfdTlv.ExpirationPeriod, endOffset);
     decoder.finishNestedTlvs(endOffset);
   }
 
   /**
    * Get Face ID
-   *
-   * @return
    */
   public int getFaceId() {
     return faceId;
@@ -101,17 +118,14 @@
 
   /**
    * Set Face ID
-   *
-   * @param faceId
    */
-  public void setFaceId(int faceId) {
+  public Route setFaceId(int faceId) {
     this.faceId = faceId;
+    return this;
   }
 
   /**
    * Get origin
-   *
-   * @return
    */
   public int getOrigin() {
     return origin;
@@ -119,17 +133,14 @@
 
   /**
    * Set origin
-   *
-   * @param origin
    */
-  public void setOrigin(int origin) {
+  public Route setOrigin(int origin) {
     this.origin = origin;
+    return this;
   }
 
   /**
    * Get cost
-   *
-   * @return
    */
   public int getCost() {
     return cost;
@@ -137,52 +148,68 @@
 
   /**
    * Set cost
-   *
-   * @param cost
    */
-  public void setCost(int cost) {
+  public Route setCost(int cost) {
     this.cost = cost;
+    return this;
   }
 
   /**
    * Get flags
-   *
-   * @return
    */
-  public ForwardingFlags getFlags() {
+  public int getFlags() {
     return flags;
   }
 
   /**
    * Set flags
-   *
-   * @param flags
    */
-  public void setFlags(ForwardingFlags flags) {
+  public void setFlags(int flags) {
     this.flags = flags;
   }
 
   /**
-   * Get expiration period
-   *
-   * @return
+   * Get expiration period (in milliseconds)
    */
-  public double getExpirationPeriod() {
+  public int getExpirationPeriod() {
     return expirationPeriod;
   }
 
   /**
+   * Check if route should not expire
+   */
+  public boolean hasInfiniteExpirationPeriod() {
+    return expirationPeriod < 0;
+  }
+
+  /**
    * Set expiration period
    *
    * @param expirationPeriod
    */
-  public void setExpirationPeriod(double expirationPeriod) {
+  public void setExpirationPeriod(int expirationPeriod) {
     this.expirationPeriod = expirationPeriod;
   }
 
-  private int faceId = -1;
-  private int origin = -1;
-  private int cost = -1;
-  private ForwardingFlags flags = new ForwardingFlags();
-  private double expirationPeriod = -1.0;
+  /**
+   * Get human-readable representation of Route
+   */
+  @Override
+  public String toString() {
+    StringBuilder out = new StringBuilder();
+    out.append("Route(");
+    out.append("FaceId: "); out.append(getFaceId()); out.append(", ");
+    out.append("Origin: "); out.append(getOrigin()); out.append(", ");
+    out.append("Cost: "); out.append(getCost()); out.append(", ");
+    out.append("Flags: "); out.append(getFlags()); out.append(", ");
+
+    if (!hasInfiniteExpirationPeriod()) {
+      out.append("ExpirationPeriod: "); out.append(getExpirationPeriod()); out.append(" milliseconds");
+    }
+    else {
+      out.append("ExpirationPeriod: Infinity");
+    }
+    out.append(")");
+    return out.toString();
+  }
 }
diff --git a/src/main/java/com/intel/jndn/management/types/StatusDataset.java b/src/main/java/com/intel/jndn/management/types/StatusDataset.java
deleted file mode 100644
index 0cc42c8..0000000
--- a/src/main/java/com/intel/jndn/management/types/StatusDataset.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 com.intel.jndn.management.ManagementException;
-import java.util.ArrayList;
-import java.util.List;
-import net.named_data.jndn.encoding.EncodingException;
-import net.named_data.jndn.encoding.tlv.TlvDecoder;
-import net.named_data.jndn.util.Blob;
-
-/**
- * Helper class to handle StatusDatasets, see
- * <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
- *
- * @author Andrew Brown <andrew.brown@intel.com>
- */
-public class StatusDataset {
-
-  /**
-   * Decode multiple status entries as part of a StatusDataset, see
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/StatusDataset">http://redmine.named-data.net/projects/nfd/wiki/StatusDataset</a>
-   *
-   * @param <T>
-   * @param statusDataset
-   * @param type
-   * @return
-   * @throws com.intel.jndn.management.ManagementException
-   */
-  public static final <T extends Decodable> List<T> wireDecode(Blob statusDataset, Class<T> type) throws ManagementException {
-    List<T> entries = new ArrayList<>();
-    int endOffset = statusDataset.size();
-    TlvDecoder decoder = new TlvDecoder(statusDataset.buf());
-    while (decoder.getOffset() < endOffset) {
-      try {
-        T entry = type.newInstance();
-        entry.wireDecode(decoder);
-        entries.add(entry);
-      } catch (EncodingException | IllegalAccessException | InstantiationException e) {
-        throw new ManagementException("Failed to read status dataset.", e);
-      }
-    }
-    return entries;
-  }
-}
diff --git a/src/main/java/com/intel/jndn/management/types/StrategyChoice.java b/src/main/java/com/intel/jndn/management/types/StrategyChoice.java
index 7718a75..7e092b2 100644
--- a/src/main/java/com/intel/jndn/management/types/StrategyChoice.java
+++ b/src/main/java/com/intel/jndn/management/types/StrategyChoice.java
@@ -13,8 +13,10 @@
  */
 package com.intel.jndn.management.types;
 
-import com.intel.jndn.management.EncodingHelper;
+import com.intel.jndn.management.helpers.EncodingHelper;
 import java.nio.ByteBuffer;
+
+import com.intel.jndn.management.enums.NfdTlv;
 import net.named_data.jndn.Name;
 import net.named_data.jndn.encoding.EncodingException;
 import net.named_data.jndn.encoding.tlv.TlvDecoder;
@@ -23,17 +25,31 @@
 
 /**
  * Represent a strategy choice entry.
- *
- * @see http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice
+ * @see <a href="http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice">StrategyChoice</a>
+
  * @author Andrew Brown <andrew.brown@intel.com>
  */
 public class StrategyChoice implements Decodable {
+  private Name name;
+  private Name strategy;
+
+  /////////////////////////////////////////////////////////////////////////////
 
   /**
-   * TLV type, see
-   * <a href="http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#TLV-TYPE-assignments">http://redmine.named-data.net/projects/nfd/wiki/StrategyChoice#TLV-TYPE-assignments</a>
+   * Default constructor
    */
-  public final static int TLV_STRATEGY_CHOICE = 128;
+  public StrategyChoice() {
+    // nothing to do
+  }
+
+  /**
+   * Constructor from wire format
+   * @param input wire format
+   * @throws EncodingException
+   */
+  public StrategyChoice(ByteBuffer input) throws EncodingException {
+    wireDecode(input);
+  }
 
   /**
    * Encode using a new TLV encoder.
@@ -55,7 +71,7 @@
     int saveLength = encoder.getLength();
     EncodingHelper.encodeStrategy(strategy, encoder);
     EncodingHelper.encodeName(name, encoder);
-    encoder.writeTypeAndLength(TLV_STRATEGY_CHOICE, encoder.getLength() - saveLength);
+    encoder.writeTypeAndLength(NfdTlv.StrategyChoice, encoder.getLength() - saveLength);
   }
 
   /**
@@ -78,7 +94,7 @@
    */
   @Override
   public final void wireDecode(TlvDecoder decoder) throws EncodingException {
-    int endOffset = decoder.readNestedTlvsStart(TLV_STRATEGY_CHOICE);
+    int endOffset = decoder.readNestedTlvsStart(NfdTlv.StrategyChoice);
     name = EncodingHelper.decodeName(decoder);
     strategy = EncodingHelper.decodeStrategy(decoder);
     decoder.finishNestedTlvs(endOffset);
@@ -101,17 +117,16 @@
   /**
    * @param name the {@link Name} to set
    */
-  public void setName(Name name) {
+  public StrategyChoice setName(Name name) {
     this.name = name;
+    return this;
   }
 
   /**
    * @param strategy the {@link Name} to set
    */
-  public void setStrategy(Name strategy) {
+  public StrategyChoice setStrategy(Name strategy) {
     this.strategy = strategy;
+    return this;
   }
-
-  private Name name;
-  private Name strategy;
 }