/**
  * Create a payment ack.
  *
  * @param paymentMessage payment message to send with the ack
  * @param memo arbitrary, user readable memo, or null if none
  * @return created payment ack
  */
 public static Protos.PaymentACK createPaymentAck(
     Protos.Payment paymentMessage, @Nullable String memo) {
   final Protos.PaymentACK.Builder builder = Protos.PaymentACK.newBuilder();
   builder.setPayment(paymentMessage);
   if (memo != null) builder.setMemo(memo);
   return builder.build();
 }
  @Override
  public Boolean call() {

    if (serverSocket.isClosed()) {
      log.warn("Server socket is closed. Aborting.");
      return false;
    } else {

      try {
        // Wait for a client connection
        log.debug("Await client connection to SSLSocket");
        SSLSocket socket = (SSLSocket) serverSocket.accept();
        socket.startHandshake();

        log.debug("Sending PaymentACK");
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream = socket.getOutputStream();

        // Read the inputStream - this is expected to be a header followed by a serialised Payment
        Reader reader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(reader);
        String line;
        int contentLength = -1;
        StringBuilder builder = new StringBuilder();
        while (!"".equals((line = bufferedReader.readLine()))) {
          builder.append(line).append("\n");
          log.debug("Read line: {}", line);
          if (line.startsWith("Content-Length")) {
            String[] tokens = line.replaceAll(" ", "").split(":");
            if (tokens.length >= 2) {
              contentLength = Integer.parseInt(tokens[1]);
            }
          }
        }
        log.debug("Calculated contentLength: {}", contentLength);
        log.debug("Read the header:\n{}\n", builder.toString());

        // Get the Content-Length and read those - this is expected to be the serialised Payment
        if (contentLength > -1) {
          byte buffer[] = new byte[contentLength];
          for (int i = 0; i < contentLength; i++) {
            buffer[i] = (byte) inputStream.read();
          }

          log.debug("Read:\n", HexUtils.toHexBytes(buffer));

          try {
            Protos.Payment payment = Protos.Payment.parseFrom(buffer);

            log.debug("Successfully parsed a payment {}", payment);

            // Create a PaymentACK for the payment
            Protos.PaymentACK paymentAck =
                PaymentProtocol.createPaymentAck(payment, "You sent: '" + payment.getMemo() + "'");

            log.debug("Sending paymentACK as a response: {}", paymentAck);
            // Write the HTTP header
            outputStream.write("HTTP/1.0 200 OK\n".getBytes(Charsets.UTF_8));
            outputStream.write("Content-Type: ".getBytes(Charsets.UTF_8));
            outputStream.write(contentType.getBytes(Charsets.UTF_8));
            outputStream.write("\n\n".getBytes(Charsets.UTF_8));

            // Write the protobuf response
            paymentAck.writeTo(outputStream);

            // ByteArrayInputStream responseInputStream = new ByteArrayInputStream(paymentAckBytes);
            // ByteStreams.copy(responseInputStream, outputStream);

          } catch (com.google.protobuf.InvalidProtocolBufferException ipbe) {
            log.error("Was expecting a Payment on the socket but saw something else");
            ipbe.printStackTrace();
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            // Release resources
            log.debug("Flush then close client socket...");
            socket.getOutputStream().flush();
            socket.close();
          }
        } else {
          log.debug("Could not find a Content-Length in the header so not reading payment");
        }
        return true;

      } catch (IOException e) {
        throw new IllegalStateException("Unexpected IOException", e);
      }
    }
  }
 /** Parse payment ack into an object. */
 public static Ack parsePaymentAck(Protos.PaymentACK paymentAck) {
   final String memo = paymentAck.hasMemo() ? paymentAck.getMemo() : null;
   return new Ack(memo);
 }