/**
  * Force the configuration master to install a new view. This method should only be called during
  * testing.
  *
  * @param v The new view to install.
  */
 @Override
 public void forceNewView(CorfuDBView v) {
   try {
     JSONRPC2Request jr = new JSONRPC2Request("newview", id.getAndIncrement());
     Map<String, Object> params = new HashMap<String, Object>();
     params.put("newview", v.getSerializedJSONView().toString());
     jr.setNamedParams(params);
     JSONRPC2Response jres = jsonSession.send(jr);
     if (jres.indicatesSuccess() && (Boolean) jres.getResult()) {}
   } catch (Exception e) {
   }
 }
  @Override
  public CorfuDBView getNewView(CorfuDBView oldView, NetworkException e) {
    /* it's null, don't change anything */
    if (e == null) {
      return oldView;
    }
    /* Is the exception for a Logging Unit? */
    if (e.protocol instanceof IWriteOnceLogUnit) {
      /* Okay, so was it a read or a write? */
      if (e.write) {
        /* in the case of a write, find the segment belonging to the protocol,
          and remove that protocol from the segment.
        */
        CorfuDBView newView = (CorfuDBView) Serializer.copyShallow(oldView);

        for (CorfuDBViewSegment segment : newView.getSegments()) {
          for (List<IServerProtocol> nodeList : segment.getGroups()) {
            if (nodeList.size() > 1) {
              nodeList.removeIf(n -> n.getFullString().equals(e.protocol.getFullString()));
            }
          }
        }

        log.info("Reconfiguring all nodes in view to new epoch " + oldView.getEpoch() + 1);
        newView.moveAllToNewEpoch(oldView.getEpoch() + 1);
        return newView;
      }
      /* for reads, we don't do anything, for now...
       */
      log.warn("Reconfigure due to read, ignoring");
      return oldView;
    } else if (e.protocol instanceof ISimpleSequencer) {
      if (oldView.getSequencers().size() <= 1) {
        log.warn(
            "Request reconfiguration of sequencers but there is no fail-over available! [available sequencers="
                + oldView.getSequencers().size()
                + "]");
        return oldView;
      } else {
        CorfuDBView newView = (CorfuDBView) Serializer.copyShallow(oldView);
        newView.moveAllToNewEpoch(oldView.getEpoch() + 1);

        /* Interrogate each log unit to figure out last issued token */
        long last = -1;
        for (CorfuDBViewSegment segment : newView.getSegments()) {
          int groupNum = 1;
          for (List<IServerProtocol> nodeList : segment.getGroups()) {
            for (IServerProtocol n : nodeList) {
              try {
                last =
                    Long.max(
                        last,
                        ((IWriteOnceLogUnit) n).highestAddress() * segment.getGroups().size()
                            + groupNum);
              } catch (NetworkException ne) {

              }
            }
            groupNum++;
          }
        }

        log.warn(
            "Removing sequencer "
                + e.protocol.getFullString()
                + " from configuration, discover last sequence was "
                + last);
        newView.getSequencers().removeIf(n -> n.getFullString().equals(e.protocol.getFullString()));
        try {
          ((ISimpleSequencer) newView.getSequencers().get(0)).recover(last);
        } catch (Exception ex) {
          log.warn("Tried to install recovered sequence from sequencer, but failed", e);
        }
        return newView;
      }
    } else {
      log.warn("Request reconfiguration for protocol we don't know how to reconfigure", e.protocol);
      return (CorfuDBView) Serializer.copyShallow(oldView);
    }
  }