public <T> T execute(Command<T> command) {
   ClientRequest restRequest = new ClientRequest(url);
   try {
     restRequest.body(MediaType.APPLICATION_XML, new JaxbCommandsRequest(deploymentId, command));
     ClientResponse<Object> response = restRequest.post(Object.class);
     if (response.getResponseStatus() == Status.OK) {
       JaxbCommandsResponse commandResponse = response.getEntity(JaxbCommandsResponse.class);
       List<JaxbCommandResponse<?>> responses = commandResponse.getResponses();
       if (responses.size() == 0) {
         return null;
       } else if (responses.size() == 1) {
         JaxbCommandResponse<?> responseObject = responses.get(0);
         if (responseObject instanceof JaxbExceptionResponse) {
           JaxbExceptionResponse exceptionResponse = (JaxbExceptionResponse) responseObject;
           String causeMessage = exceptionResponse.getCauseMessage();
           throw new RuntimeException(
               exceptionResponse.getMessage()
                   + (causeMessage == null ? "" : " Caused by: " + causeMessage));
         } else {
           return (T) responseObject.getResult();
         }
       } else {
         throw new RuntimeException("Unexpected number of results: " + responses.size());
       }
     } else {
       // TODO error handling
       throw new RuntimeException("REST request error code " + response.getResponseStatus());
     }
   } catch (Exception e) {
     throw new RuntimeException("Unable to execute REST request: " + e.getMessage(), e);
   }
 }
  /**
   * Method to communicate with the backend via REST.
   *
   * @param command The {@link Command} object to be executed.
   * @return The result of the {@link Command} object execution.
   */
  private <T> T executeRestCommand(Command command) {
    String cmdName = command.getClass().getSimpleName();

    JaxbCommandsRequest jaxbRequest =
        prepareCommandRequest(
            command,
            config.getUserName(),
            config.getDeploymentId(),
            config.getProcessInstanceId(),
            config.getCorrelationProperties());
    KieRemoteHttpRequest httpRequest = config.createHttpRequest().relativeRequest("/execute");

    // necessary for deserialization
    String deploymentId = config.getDeploymentId();
    if (!emptyDeploymentId(deploymentId)) {
      httpRequest.header(JaxbSerializationProvider.EXECUTE_DEPLOYMENT_ID_HEADER, deploymentId);
    }

    String jaxbRequestString = config.getJaxbSerializationProvider().serialize(jaxbRequest);
    if (logger.isTraceEnabled()) {
      try {
        logger.trace(
            "Sending {} via POST to {}", command.getClass().getSimpleName(), httpRequest.getUri());
      } catch (Exception e) {
        // do nothing because this should never happen..
      }
      logger.trace("Serialized JaxbCommandsRequest:\n {}", jaxbRequestString);
    }

    KieRemoteHttpResponse httpResponse = null;
    try {
      logger.debug(
          "Sending POST request with "
              + command.getClass().getSimpleName()
              + " to "
              + httpRequest.getUri());
      httpRequest.contentType(MediaType.APPLICATION_XML);
      httpRequest.accept(MediaType.APPLICATION_XML);
      httpRequest.body(jaxbRequestString);
      httpRequest.post();
      httpResponse = httpRequest.response();
    } catch (Exception e) {
      httpRequest.disconnect();
      throw new RemoteCommunicationException("Unable to send HTTP POST request", e);
    }

    // Get response
    boolean htmlException = false;
    JaxbExceptionResponse exceptionResponse = null;
    JaxbCommandsResponse cmdResponse = null;
    int responseStatus;
    try {
      responseStatus = httpResponse.code();
      String content = httpResponse.body();
      if (responseStatus < 300) {
        cmdResponse = deserializeResponseContent(content, JaxbCommandsResponse.class);

        // check version
        String version = cmdResponse.getVersion();
        if (version == null) {
          version = "pre-6.0.3";
        }
        if (!version.equals(VERSION)) {
          logger.info(
              "Response received from server version [{}] while client is version [{}]! This may cause problems.",
              version,
              VERSION);
        }
      } else {
        String contentType = httpResponse.contentType();
        if (contentType.equals(MediaType.APPLICATION_XML)) {
          Object response = deserializeResponseContent(content, JaxbExceptionResponse.class);
          if (response instanceof JaxbRestRequestException) {
            JaxbRestRequestException exception = (JaxbRestRequestException) response;
            exceptionResponse =
                new JaxbExceptionResponse(
                    exception.getUrl(), exception.getCause(), exception.getStatus());
            exceptionResponse.setCommandName(cmdName);
            exceptionResponse.setIndex(0);
            exceptionResponse.setMessage(exception.getMessage());
          } else if (response instanceof JaxbExceptionResponse) {
            exceptionResponse = (JaxbExceptionResponse) response;
          }
        } else if (contentType.startsWith(MediaType.TEXT_HTML)) {
          htmlException = true;
          exceptionResponse = new JaxbExceptionResponse();
          Document doc = Jsoup.parse(content);
          String body = doc.body().text();
          exceptionResponse.setMessage(body);
          exceptionResponse.setUrl(httpRequest.getUri().toString());
          exceptionResponse.setStackTrace("");
        } else {
          throw new RemoteCommunicationException(
              "Unable to deserialize response with content type '" + contentType + "'");
        }
      }
    } catch (Exception e) {
      logger.error(
          "Unable to retrieve response content from request with status {}: {}", e.getMessage(), e);
      throw new RemoteCommunicationException("Unable to retrieve content from response", e);
    } finally {
      httpRequest.disconnect();
    }

    if (cmdResponse != null) {
      List<JaxbCommandResponse<?>> responses = cmdResponse.getResponses();
      if (responses.size() == 0) {
        return null;
      } else if (responses.size() == 1) {
        // The type information *should* come from the Command class -- but it's a jaxb-gen class,
        // which means that it has lost it's type information..
        // TODO: fix this?
        JaxbCommandResponse<T> responseObject = (JaxbCommandResponse<T>) responses.get(0);
        if (responseObject instanceof JaxbExceptionResponse) {
          exceptionResponse = (JaxbExceptionResponse) responseObject;
        } else {
          return responseObject.getResult();
        }
      } else {
        throw new RemoteCommunicationException(
            "Unexpected number of results from "
                + command.getClass().getSimpleName()
                + ":"
                + responses.size()
                + " results instead of only 1");
      }
    }

    logger.error("Response with status {} returned.", responseStatus);
    // Process exception response
    switch (responseStatus) {
      case 409:
        throw new RemoteTaskException(
            exceptionResponse.getMessage(), exceptionResponse.getStackTrace());
      default:
        if (exceptionResponse != null) {
          if (!htmlException) {
            throw new RemoteApiException(
                exceptionResponse.getMessage(), exceptionResponse.getStackTrace());
          } else {
            throw new RemoteCommunicationException(
                exceptionResponse.getMessage(), exceptionResponse.getStackTrace());
          }
        } else {
          throw new RemoteCommunicationException(
              "Unable to communicate with remote API via URL "
                  + "'"
                  + httpRequest.getUri().toString()
                  + "'");
        }
    }
  }
  @Test
  @Ignore("JMS isn't working.. :/")
  public void testJmsStartProcess() throws Exception {
    // send cmd
    Command<?> cmd = new StartProcessCommand("org.jbpm.humantask");
    JaxbCommandsRequest req = new JaxbCommandsRequest(DEPLOYMENT_ID, cmd);
    JaxbCommandsResponse response = sendJmsJaxbCommandsRequest(TASK_QUEUE_NAME, req);

    // check response
    assertNotNull("response was null.", response);
    assertTrue(
        "response did not contain any command responses",
        response.getResponses() != null && response.getResponses().size() > 0);
    JaxbCommandResponse<?> cmdResponse = response.getResponses().get(0);
    assertTrue(
        "response is not the proper class type : " + cmdResponse.getClass().getSimpleName(),
        cmdResponse instanceof JaxbProcessInstanceResponse);
    ProcessInstance procInst = (ProcessInstance) cmdResponse;
    long procInstId = procInst.getId();

    // send cmd
    cmd = new GetTasksByProcessInstanceIdCommand(procInstId);
    req = new JaxbCommandsRequest(DEPLOYMENT_ID, cmd);
    response = sendJmsJaxbCommandsRequest(TASK_QUEUE_NAME, req);

    // check response
    assertNotNull("response was null.", response);
    assertTrue(
        "response did not contain any command responses",
        response.getResponses() != null && response.getResponses().size() > 0);
    cmdResponse = response.getResponses().get(0);
    assertTrue(
        "response is not the proper class type : " + cmdResponse.getClass().getSimpleName(),
        cmdResponse instanceof JaxbLongListResponse);
    long taskId = ((JaxbLongListResponse) cmdResponse).getResult().get(0);

    // send cmd
    cmd = new StartTaskCommand(taskId, USER_ID);
    req = new JaxbCommandsRequest(DEPLOYMENT_ID, cmd);
    req.getCommands().add(new CompleteTaskCommand(taskId, USER_ID, null));
    response = sendJmsJaxbCommandsRequest(TASK_QUEUE_NAME, req);

    // check response
    assertNotNull("response was null.", response);
    assertTrue("response list was not empty", response.getResponses().size() == 0);

    // send cmd
    cmd = new GetTasksOwnedCommand(USER_ID, "en-UK");
    req = new JaxbCommandsRequest(DEPLOYMENT_ID, cmd);
    req.getCommands().add(new GetTasksOwnedCommand("bob", "fr-CA"));
    req.getCommands().add(new GetProcessInstanceCommand(procInstId));
    response = sendJmsJaxbCommandsRequest(TASK_QUEUE_NAME, req);

    assertNotNull("response was null.", response);
    assertTrue(
        "response did not contain any command responses",
        response.getResponses() != null && response.getResponses().size() > 0);
    cmdResponse = response.getResponses().get(0);
    assertTrue(
        "response is not the proper class type : " + cmdResponse.getClass().getSimpleName(),
        cmdResponse instanceof JaxbTaskSummaryListResponse);
    List<TaskSummary> taskSummaries = ((JaxbTaskSummaryListResponse) cmdResponse).getResult();
    assertTrue("task summary list is empty", taskSummaries.size() > 0);
    for (TaskSummary taskSum : taskSummaries) {
      if (taskSum.getId() == taskId) {
        assertTrue(
            "Task " + taskId + " should have completed.",
            taskSum.getStatus().equals(Status.Completed));
      }
    }

    cmdResponse = response.getResponses().get(1);
    assertTrue(
        "response is not the proper class type : " + cmdResponse.getClass().getSimpleName(),
        cmdResponse instanceof JaxbTaskSummaryListResponse);
    taskSummaries = ((JaxbTaskSummaryListResponse) cmdResponse).getResult();
    assertTrue(
        "task summary list should be empty, but has " + taskSummaries.size() + " elements",
        taskSummaries.size() == 0);
    cmdResponse = response.getResponses().get(2);
    assertNotNull(cmdResponse);
  }