docs: protected void doAction(final HttpServletRequest req, final HttpServletResponse resp, String action) {
          // Read the request.
          ApiRequest srequest;
          try {
              srequest = readRequest(req);
              srequest.setType(action);
          } catch (Exception e) {
              writeError(null, resp, e);
              return;
          }
  
          final CountDownLatch latch = new CountDownLatch(1);
          final ApiRequest finalRequest = srequest;
  
          // Now execute the request via the apiman engine
          IApiRequestExecutor executor = getEngine().executor(srequest, new IAsyncResultHandler<IEngineResult>() {
              @Override
              public void handle(IAsyncResult<IEngineResult> asyncResult) {
                  if (asyncResult.isSuccess()) {
                      IEngineResult engineResult = asyncResult.getResult();
                      if (engineResult.isResponse()) {
                          try {
                              writeResponse(resp, engineResult.getApiResponse());
                              final ServletOutputStream outputStream = resp.getOutputStream();
                              engineResult.bodyHandler(new IAsyncHandler<IApimanBuffer>() {
                                  @Override
                                  public void handle(IApimanBuffer chunk) {
                                      try {
                                          if (chunk instanceof ByteBuffer) {
                                              byte [] buffer = (byte []) chunk.getNativeBuffer();
                                              outputStream.write(buffer, 0, chunk.length());
                                          } else {
                                              outputStream.write(chunk.getBytes());
                                          }
                                      } catch (IOException e) {
                                          // This will get caught by the API connector, which will abort the
                                          // connection to the back-end API.
                                          throw new RuntimeException(e);
                                      }
                                  }
                              });
                              engineResult.endHandler(new IAsyncHandler<Void>() {
                                  @Override
                                  public void handle(Void result) {
                                      try {
                                          resp.flushBuffer();
                                      } catch (IOException e) {
                                          // This will get caught by the API connector, which will abort the
                                          // connection to the back-end API.
                                          throw new RuntimeException(e);
                                      } finally {
                                          latch.countDown();
                                      }
                                  }
                              });
                          } catch (IOException e) {
                              // this would mean we couldn't get the output stream from the response, so we
                              // need to abort the engine result (which will let the back-end connection
                              // close down).
                              engineResult.abort(e);
                              latch.countDown();
                              throw new RuntimeException(e);
                          }
                      } else {
                          writeFailure(finalRequest, resp, engineResult.getPolicyFailure());
                          latch.countDown();
                      }
                  } else {
                      writeError(finalRequest, resp, asyncResult.getError());
                      latch.countDown();
                  }
              }
          });
          executor.streamHandler(new IAsyncHandler<ISignalWriteStream>() {
              @Override
              public void handle(ISignalWriteStream connectorStream) {
                  try {
                      final InputStream is = req.getInputStream();
                      ByteBuffer buffer = new ByteBuffer(2048);
                      int numBytes = buffer.readFrom(is);
                      while (numBytes != -1) {
                          connectorStream.write(buffer);
                          numBytes = buffer.readFrom(is);
                      }
                      connectorStream.end();
                  } catch (Throwable e) {
                      connectorStream.abort(e);
                  }
              }
          });
          executor.execute();
          try { latch.await(); } catch (InterruptedException e) { }
      }