@Override
 public byte[] handle(byte[] requestBa) {
   ClassLoadingCodeRunnerClient.RemoteCodeRequest request =
       (ClassLoadingCodeRunnerClient.RemoteCodeRequest)
           SerializationHelper.toObject(requestBa, getClass().getClassLoader());
   ClassLoadingCodeRunnerClient.log.debug("handling {}", request);
   try {
     return SerializationHelper.toByteArray(handle(request));
   } catch (Exception e) {
     return SerializationHelper.toByteArray(new FailureResponse(e));
   } finally {
     ClassLoadingCodeRunnerClient.log.debug(
         "handling " + request.getClass().getSimpleName() + " done");
   }
 }
  @SuppressWarnings("unchecked")
  private ClassLoadingCodeRunnerClient.RemoteCodeResponse handle(
      ClassLoadingCodeRunnerClient.RemoteCodeRequest request) {
    if (request instanceof ClassLoadingCodeRunnerClient.GetToClientMessagesRequest) {
      List<ClassLoadingCodeRunnerClient.RemoteCodeMessage> messages = new ArrayList<>();
      try {
        messages.add(toClient.take());
      } catch (InterruptedException e) {
        throw new RuntimeException(e);
      }
      toClient.drainTo(messages);
      ClassLoadingCodeRunnerClient.log.debug("sending to client: {}", messages);
      return new ToClientMessagesResponse(messages);
    } else if (request instanceof ClassLoadingCodeRunnerClient.SendToServerMessagesRequest) {
      ClassLoadingCodeRunnerClient.SendToServerMessagesRequest sendToServerMessagesRequest =
          (ClassLoadingCodeRunnerClient.SendToServerMessagesRequest) request;
      for (ClassLoadingCodeRunnerClient.RemoteCodeMessage message :
          sendToServerMessagesRequest.messages) {
        ClassLoadingCodeRunnerClient.log.debug("handling toServer message " + message);
        if (message instanceof ClassLoadingCodeRunnerClient.ServerCodeExitReceived) {
          toServerDeserializer.shutdown();
          exitConfirmationReceived.release();
        } else if (message instanceof ClassLoadingCodeRunnerClient.SendResourceMessage) {
          classLoader.addResource((ClassLoadingCodeRunnerClient.SendResourceMessage) message);
        } else if (message instanceof ClassLoadingCodeRunnerClient.SendJarsMessage) {
          classLoader.addJars(((ClassLoadingCodeRunnerClient.SendJarsMessage) message).jars);
        } else if (message instanceof ClassLoadingCodeRunnerClient.CustomMessageWrapper) {
          toServerDeserializer.execute(
              () -> {
                ClassLoadingCodeRunnerClient.CustomMessageWrapper wrapper =
                    (ClassLoadingCodeRunnerClient.CustomMessageWrapper) message;
                TMessage wrappedMessage =
                    (TMessage) SerializationHelper.toObject(wrapper.message, classLoader);
                ClassLoadingCodeRunnerClient.log.debug(
                    "received and deserialized custom message {}", wrappedMessage);
                toServer.add(wrappedMessage);
              });
        } else {
          throw new UnsupportedOperationException("Unknown message " + message);
        }
      }

      return new EmptyResponse();
    } else {
      throw new UnsupportedOperationException(request.getClass().getName());
    }
  }