/** Shutdown the processor. */
 public void shutdown() {
   LOG.info("Shutting down");
   finished = true;
   queuedRequests.clear();
   queuedRequests.add(Request.requestOfDeath);
   nextProcessor.shutdown();
 }
  @Override
  public void run() {
    try {
      while (!finished) {
        Request request = queuedRequests.take();
        if (LOG.isTraceEnabled()) {
          ZooTrace.logRequest(LOG, ZooTrace.CLIENT_REQUEST_TRACE_MASK, 'F', request, "");
        }
        if (request == Request.requestOfDeath) {
          break;
        }
        // We want to queue the request to be processed before we submit
        // the request to the leader so that we are ready to receive
        // the response
        nextProcessor.processRequest(request);

        // We now ship the request to the leader. As with all
        // other quorum operations, sync also follows this code
        // path, but different from others, we need to keep track
        // of the sync operations this Observer has pending, so we
        // add it to pendingSyncs.
        switch (request.type) {
          case OpCode.sync:
            zks.pendingSyncs.add(request);
            zks.getObserver().request(request);
            break;
          case OpCode.create:
          case OpCode.create2:
          case OpCode.delete:
          case OpCode.setData:
          case OpCode.reconfig:
          case OpCode.setACL:
          case OpCode.multi:
          case OpCode.check:
            zks.getObserver().request(request);
            break;
          case OpCode.createSession:
          case OpCode.closeSession:
            // Don't forward local sessions to the leader.
            if (!request.isLocalSession()) {
              zks.getObserver().request(request);
            }
            break;
        }
      }
    } catch (Exception e) {
      LOG.error("Unexpected exception causing exit", e);
    }
    LOG.info("ObserverRequestProcessor exited loop!");
  }