@Override
  public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
    NodeId master = mastershipService.getMasterFor(deviceId);

    if (master == null) {
      log.debug("Failed to getFlowEntries: No master for {}", deviceId);
      return Collections.emptyList();
    }

    if (Objects.equal(local, master)) {
      return flowTable.getFlowEntries(deviceId);
    }

    log.trace(
        "Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
        master,
        deviceId);

    return Tools.futureGetOrElse(
        clusterCommunicator.sendAndReceive(
            deviceId,
            FlowStoreMessageSubjects.GET_DEVICE_FLOW_ENTRIES,
            SERIALIZER::encode,
            SERIALIZER::decode,
            master),
        FLOW_RULE_STORE_TIMEOUT_MILLIS,
        TimeUnit.MILLISECONDS,
        Collections.emptyList());
  }
  @Override
  public FlowEntry getFlowEntry(FlowRule rule) {
    NodeId master = mastershipService.getMasterFor(rule.deviceId());

    if (master == null) {
      log.debug("Failed to getFlowEntry: No master for {}", rule.deviceId());
      return null;
    }

    if (Objects.equal(local, master)) {
      return flowTable.getFlowEntry(rule);
    }

    log.trace(
        "Forwarding getFlowEntry to {}, which is the primary (master) for device {}",
        master,
        rule.deviceId());

    return Tools.futureGetOrElse(
        clusterCommunicator.sendAndReceive(
            rule,
            FlowStoreMessageSubjects.GET_FLOW_ENTRY,
            SERIALIZER::encode,
            SERIALIZER::decode,
            master),
        FLOW_RULE_STORE_TIMEOUT_MILLIS,
        TimeUnit.MILLISECONDS,
        null);
  }
  @Override
  public Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint) {
    final DeviceId deviceId = connectPoint.deviceId();

    NodeId master = mastershipService.getMasterFor(deviceId);
    if (master == null) {
      log.warn("No master for {}", deviceId);
      return Collections.emptySet();
    }

    if (Objects.equal(local, master)) {
      return getPreviousStatisticInternal(connectPoint);
    } else {
      return Tools.futureGetOrElse(
          clusterCommunicator.sendAndReceive(
              connectPoint, GET_PREVIOUS, SERIALIZER::encode, SERIALIZER::decode, master),
          STATISTIC_STORE_TIMEOUT_MILLIS,
          TimeUnit.MILLISECONDS,
          Collections.emptySet());
    }
  }