/**
   * Method to communicate with the backend via JMS.
   *
   * @param command The {@link Command} object to be executed.
   * @return The result of the {@link Command} object execution.
   */
  private <T> T executeJmsCommand(Command command) {

    Queue sendQueue;
    boolean isTaskCommand = (command instanceof TaskCommand);
    if (isTaskCommand) {
      sendQueue = config.getTaskQueue();
      if (!config.getUseUssl() && !config.getDisableTaskSecurity()) {
        throw new RemoteCommunicationException(
            "Task operation requests can only be sent via JMS if SSL is used.");
      }
    } else {
      sendQueue = config.getKsessionQueue();
    }

    return internalExecuteJmsCommand(
        command,
        config.getConnectionUserName(),
        config.getConnectionPassword(),
        config.getUserName(),
        config.getPassword(),
        config.getDeploymentId(),
        config.getProcessInstanceId(),
        config.getCorrelationProperties(),
        config.getConnectionFactory(),
        sendQueue,
        config.getResponseQueue(),
        (SerializationProvider) config.getJaxbSerializationProvider(),
        config.getExtraJaxbClasses(),
        config.getSerializationType(),
        config.getTimeout());
  }
 void preprocessCommand(Command cmd) {
   String cmdName = cmd.getClass().getSimpleName();
   if (cmd instanceof TaskCommand && cmdName.startsWith("GetTask")) {
     TaskCommand taskCmd = (TaskCommand) cmd;
     String cmdUserId = taskCmd.getUserId();
     String authUserId = config.getUserName();
     if (cmdUserId == null) {
       taskCmd.setUserId(authUserId);
       logger.debug("Using user id '" + authUserId + "' for '" + cmdName + "'.");
     } else if (!cmdUserId.equals(authUserId)) {
       throw new RemoteApiException(
           "The user id used when retrieving task information ("
               + cmdUserId
               + ")"
               + " must match the authenticating user ("
               + authUserId
               + ")!");
     }
   }
 }
  /**
   * 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()
                  + "'");
        }
    }
  }