protected void addGlobalVariables(
      Execution execution,
      int variableType,
      Map<String, RestVariable> variableMap,
      UriInfo uriInfo) {
    RuntimeService runtimeService = BPMNOSGIService.getRumtimeService();
    Map<String, Object> rawVariables = runtimeService.getVariables(execution.getId());
    List<RestVariable> globalVariables =
        new RestResponseFactory()
            .createRestVariables(
                rawVariables,
                execution.getId(),
                variableType,
                RestVariable.RestVariableScope.GLOBAL,
                uriInfo.getBaseUri().toString());

    // Overlay global variables over local ones. In case they are present the values are not
    // overridden,
    // since local variables get precedence over global ones at all times.
    for (RestVariable var : globalVariables) {
      if (!variableMap.containsKey(var.getName())) {
        variableMap.put(var.getName(), var);
      }
    }
  }
 static {
   allowedSortProperties.put("processDefinitionId", ExecutionQueryProperty.PROCESS_DEFINITION_ID);
   allowedSortProperties.put(
       "processDefinitionKey", ExecutionQueryProperty.PROCESS_DEFINITION_KEY);
   allowedSortProperties.put("processInstanceId", ExecutionQueryProperty.PROCESS_INSTANCE_ID);
   allowedSortProperties.put("tenantId", ExecutionQueryProperty.TENANT_ID);
 }
  protected Map<String, Object> getVariablesToSet(ExecutionActionRequest actionRequest) {
    Map<String, Object> variablesToSet = new HashMap<String, Object>();
    for (RestVariable var : actionRequest.getVariables()) {
      if (var.getName() == null) {
        throw new ActivitiIllegalArgumentException("Variable name is required");
      }

      Object actualVariableValue = new RestResponseFactory().getVariableValue(var);

      variablesToSet.put(var.getName(), actualVariableValue);
    }
    return variablesToSet;
  }
  protected List<RestVariable> processVariables(
      Execution execution, String scope, int variableType, UriInfo uriInfo) {
    List<RestVariable> result = new ArrayList<RestVariable>();
    Map<String, RestVariable> variableMap = new HashMap<String, RestVariable>();

    // Check if it's a valid execution to get the variables for
    RestVariable.RestVariableScope variableScope = RestVariable.getScopeFromString(scope);

    if (variableScope == null) {
      // Use both local and global variables
      addLocalVariables(execution, variableType, variableMap, uriInfo);
      addGlobalVariables(execution, variableType, variableMap, uriInfo);

    } else if (variableScope == RestVariable.RestVariableScope.GLOBAL) {
      addGlobalVariables(execution, variableType, variableMap, uriInfo);

    } else if (variableScope == RestVariable.RestVariableScope.LOCAL) {
      addLocalVariables(execution, variableType, variableMap, uriInfo);
    }

    // Get unique variables from map
    result.addAll(variableMap.values());
    return result;
  }
  protected void addLocalVariables(
      Execution execution,
      int variableType,
      Map<String, RestVariable> variableMap,
      UriInfo uriInfo) {
    RuntimeService runtimeService = BPMNOSGIService.getRumtimeService();
    Map<String, Object> rawLocalvariables = runtimeService.getVariablesLocal(execution.getId());
    List<RestVariable> localVariables =
        new RestResponseFactory()
            .createRestVariables(
                rawLocalvariables,
                execution.getId(),
                variableType,
                RestVariable.RestVariableScope.LOCAL,
                uriInfo.getBaseUri().toString());

    for (RestVariable var : localVariables) {
      variableMap.put(var.getName(), var);
    }
  }
  protected DataResponse getQueryResponse(
      ExecutionQueryRequest queryRequest, Map<String, String> requestParams, UriInfo uriInfo) {

    RuntimeService runtimeService = BPMNOSGIService.getRumtimeService();
    ExecutionQuery query = runtimeService.createExecutionQuery();

    // Populate query based on request
    if (queryRequest.getId() != null) {
      query.executionId(queryRequest.getId());
      requestParams.put("id", queryRequest.getId());
    }
    if (queryRequest.getProcessInstanceId() != null) {
      query.processInstanceId(queryRequest.getProcessInstanceId());
      requestParams.put("processInstanceId", queryRequest.getProcessInstanceId());
    }
    if (queryRequest.getProcessDefinitionKey() != null) {
      query.processDefinitionKey(queryRequest.getProcessDefinitionKey());
      requestParams.put("processDefinitionKey", queryRequest.getProcessDefinitionKey());
    }
    if (queryRequest.getProcessDefinitionId() != null) {
      query.processDefinitionId(queryRequest.getProcessDefinitionId());
      requestParams.put("processDefinitionId", queryRequest.getProcessDefinitionId());
    }
    if (queryRequest.getProcessBusinessKey() != null) {
      query.processInstanceBusinessKey(queryRequest.getProcessBusinessKey());
      requestParams.put("processInstanceBusinessKey", queryRequest.getProcessBusinessKey());
    }
    if (queryRequest.getActivityId() != null) {
      query.activityId(queryRequest.getActivityId());
      requestParams.put("activityId", queryRequest.getActivityId());
    }
    if (queryRequest.getParentId() != null) {
      query.parentId(queryRequest.getParentId());
      requestParams.put("parentId", queryRequest.getParentId());
    }
    if (queryRequest.getMessageEventSubscriptionName() != null) {
      query.messageEventSubscriptionName(queryRequest.getMessageEventSubscriptionName());
      requestParams.put(
          "messageEventSubscriptionName", queryRequest.getMessageEventSubscriptionName());
    }
    if (queryRequest.getSignalEventSubscriptionName() != null) {
      query.signalEventSubscriptionName(queryRequest.getSignalEventSubscriptionName());
      requestParams.put(
          "signalEventSubscriptionName", queryRequest.getSignalEventSubscriptionName());
    }

    if (queryRequest.getVariables() != null) {
      addVariables(query, queryRequest.getVariables(), false);
    }

    if (queryRequest.getProcessInstanceVariables() != null) {
      addVariables(query, queryRequest.getProcessInstanceVariables(), true);
    }

    if (queryRequest.getTenantId() != null) {
      query.executionTenantId(queryRequest.getTenantId());
      requestParams.put("tenantId", queryRequest.getTenantId());
    }

    if (queryRequest.getTenantIdLike() != null) {
      query.executionTenantIdLike(queryRequest.getTenantIdLike());
      requestParams.put("tenantIdLike", queryRequest.getTenantIdLike());
    }

    if (Boolean.TRUE.equals(queryRequest.getWithoutTenantId())) {
      query.executionWithoutTenantId();
      requestParams.put("withoutTenantId", queryRequest.getWithoutTenantId().toString());
    }

    DataResponse dataResponse =
        new ExecutionPaginateList(new RestResponseFactory(), uriInfo)
            .paginateList(
                requestParams, queryRequest, query, "processInstanceId", allowedSortProperties);
    return dataResponse;
  }
  protected Response createExecutionVariable(
      Execution execution,
      boolean override,
      int variableType,
      HttpServletRequest httpServletRequest,
      UriInfo uriInfo) {

    Object result = null;
    Response.ResponseBuilder responseBuilder = Response.ok();

    List<RestVariable> inputVariables = new ArrayList<>();
    List<RestVariable> resultVariables = new ArrayList<>();

    if (Utils.isApplicationJsonRequest(httpServletRequest)) {
      try {
        ObjectMapper objectMapper = new ObjectMapper();
        @SuppressWarnings("unchecked")
        List<Object> variableObjects =
            (List<Object>) objectMapper.readValue(httpServletRequest.getInputStream(), List.class);
        for (Object restObject : variableObjects) {
          RestVariable restVariable = objectMapper.convertValue(restObject, RestVariable.class);
          inputVariables.add(restVariable);
        }
      } catch (Exception e) {
        throw new ActivitiIllegalArgumentException(
            "Failed to serialize to a RestVariable instance", e);
      }
    } else if (Utils.isApplicationXmlRequest(httpServletRequest)) {
      JAXBContext jaxbContext = null;
      try {
        jaxbContext = JAXBContext.newInstance(RestVariableCollection.class);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        RestVariableCollection restVariableCollection =
            (RestVariableCollection)
                jaxbUnmarshaller.unmarshal(httpServletRequest.getInputStream());
        if (restVariableCollection == null) {
          throw new ActivitiIllegalArgumentException(
              "xml request body could not be transformed to a "
                  + "RestVariable Collection instance.");
        }
        List<RestVariable> restVariableList = restVariableCollection.getRestVariables();

        if (restVariableList.size() == 0) {
          throw new ActivitiIllegalArgumentException(
              "xml request body could not identify any rest " + "variables to be updated");
        }
        for (RestVariable restVariable : restVariableList) {
          inputVariables.add(restVariable);
        }

      } catch (JAXBException | IOException e) {
        throw new ActivitiIllegalArgumentException(
            "xml request body could not be transformed to a " + "RestVariable instance.", e);
      }
    }

    if (inputVariables.size() == 0) {
      throw new ActivitiIllegalArgumentException(
          "Request didn't contain a list of variables to create.");
    }

    RestVariable.RestVariableScope sharedScope = null;
    RestVariable.RestVariableScope varScope = null;
    Map<String, Object> variablesToSet = new HashMap<String, Object>();

    for (RestVariable var : inputVariables) {
      // Validate if scopes match
      varScope = var.getVariableScope();
      if (var.getName() == null) {
        throw new ActivitiIllegalArgumentException("Variable name is required");
      }

      if (varScope == null) {
        varScope = RestVariable.RestVariableScope.LOCAL;
      }
      if (sharedScope == null) {
        sharedScope = varScope;
      }
      if (varScope != sharedScope) {
        throw new ActivitiIllegalArgumentException(
            "Only allowed to update multiple variables in the same scope.");
      }

      if (!override && hasVariableOnScope(execution, var.getName(), varScope)) {
        throw new BPMNConflictException(
            "Variable '"
                + var.getName()
                + "' is already present on execution '"
                + execution.getId()
                + "'.");
      }

      Object actualVariableValue = new RestResponseFactory().getVariableValue(var);
      variablesToSet.put(var.getName(), actualVariableValue);
      resultVariables.add(
          new RestResponseFactory()
              .createRestVariable(
                  var.getName(),
                  actualVariableValue,
                  varScope,
                  execution.getId(),
                  variableType,
                  false,
                  uriInfo.getBaseUri().toString()));
    }

    if (!variablesToSet.isEmpty()) {
      RuntimeService runtimeService = BPMNOSGIService.getRumtimeService();
      if (sharedScope == RestVariable.RestVariableScope.LOCAL) {
        runtimeService.setVariablesLocal(execution.getId(), variablesToSet);
      } else {
        if (execution.getParentId() != null) {
          // Explicitly set on parent, setting non-local variables on execution itself will override
          // local-variables if exists
          runtimeService.setVariables(execution.getParentId(), variablesToSet);
        } else {
          // Standalone task, no global variables possible
          throw new ActivitiIllegalArgumentException(
              "Cannot set global variables on execution '"
                  + execution.getId()
                  + "', task is not part of process.");
        }
      }
    }

    RestVariableCollection restVariableCollection = new RestVariableCollection();
    restVariableCollection.setRestVariables(resultVariables);
    responseBuilder.entity(restVariableCollection);
    return responseBuilder.status(Response.Status.CREATED).build();
  }
  protected RestVariable createBinaryExecutionVariable(
      Execution execution,
      int responseVariableType,
      UriInfo uriInfo,
      boolean isNew,
      MultipartBody multipartBody) {

    boolean debugEnabled = log.isDebugEnabled();
    Response.ResponseBuilder responseBuilder = Response.ok();

    List<org.apache.cxf.jaxrs.ext.multipart.Attachment> attachments =
        multipartBody.getAllAttachments();

    int attachmentSize = attachments.size();

    if (attachmentSize <= 0) {
      throw new ActivitiIllegalArgumentException("No Attachments found with the request body");
    }
    AttachmentDataHolder attachmentDataHolder = new AttachmentDataHolder();

    for (int i = 0; i < attachmentSize; i++) {
      org.apache.cxf.jaxrs.ext.multipart.Attachment attachment = attachments.get(i);

      String contentDispositionHeaderValue = attachment.getHeader("Content-Disposition");
      String contentType = attachment.getHeader("Content-Type");

      if (debugEnabled) {
        log.debug("Going to iterate:" + i);
        log.debug("contentDisposition:" + contentDispositionHeaderValue);
      }

      if (contentDispositionHeaderValue != null) {
        contentDispositionHeaderValue = contentDispositionHeaderValue.trim();

        Map<String, String> contentDispositionHeaderValueMap =
            Utils.processContentDispositionHeader(contentDispositionHeaderValue);
        String dispositionName = contentDispositionHeaderValueMap.get("name");
        DataHandler dataHandler = attachment.getDataHandler();

        OutputStream outputStream = null;

        if ("name".equals(dispositionName)) {
          try {
            outputStream = Utils.getAttachmentStream(dataHandler.getInputStream());
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException("Attachment Name Reading error occured", e);
          }

          if (outputStream != null) {
            String fileName = outputStream.toString();
            attachmentDataHolder.setName(fileName);
          }

        } else if ("type".equals(dispositionName)) {
          try {
            outputStream = Utils.getAttachmentStream(dataHandler.getInputStream());
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException("Attachment Type Reading error occured", e);
          }

          if (outputStream != null) {
            String typeName = outputStream.toString();
            attachmentDataHolder.setType(typeName);
          }

        } else if ("scope".equals(dispositionName)) {
          try {
            outputStream = Utils.getAttachmentStream(dataHandler.getInputStream());
          } catch (IOException e) {
            throw new ActivitiIllegalArgumentException(
                "Attachment Description Reading error occured", e);
          }

          if (outputStream != null) {
            String description = outputStream.toString();
            attachmentDataHolder.setScope(description);
          }
        }

        if (contentType != null) {
          if ("file".equals(dispositionName)) {

            InputStream inputStream = null;
            try {
              inputStream = dataHandler.getInputStream();
            } catch (IOException e) {
              throw new ActivitiIllegalArgumentException(
                  "Error Occured During processing empty body.", e);
            }

            if (inputStream != null) {
              attachmentDataHolder.setContentType(contentType);
              byte[] attachmentArray = new byte[0];
              try {
                attachmentArray = IOUtils.toByteArray(inputStream);
              } catch (IOException e) {
                throw new ActivitiIllegalArgumentException("Processing Attachment Body Failed.", e);
              }
              attachmentDataHolder.setAttachmentArray(attachmentArray);
            }
          }
        }
      }
    }

    attachmentDataHolder.printDebug();

    if (attachmentDataHolder.getName() == null) {
      throw new ActivitiIllegalArgumentException("Attachment name is required.");
    }

    if (attachmentDataHolder.getAttachmentArray() == null) {
      throw new ActivitiIllegalArgumentException(
          "Empty attachment body was found in request body after " + "decoding the request" + ".");
    }
    String variableScope = attachmentDataHolder.getScope();
    String variableName = attachmentDataHolder.getName();
    String variableType = attachmentDataHolder.getType();

    if (log.isDebugEnabled()) {
      log.debug(
          "variableScope:"
              + variableScope
              + " variableName:"
              + variableName
              + " variableType:"
              + variableType);
    }

    try {

      // Validate input and set defaults
      if (variableName == null) {
        throw new ActivitiIllegalArgumentException("No variable name was found in request body.");
      }

      if (variableType != null) {
        if (!RestResponseFactory.BYTE_ARRAY_VARIABLE_TYPE.equals(variableType)
            && !RestResponseFactory.SERIALIZABLE_VARIABLE_TYPE.equals(variableType)) {
          throw new ActivitiIllegalArgumentException(
              "Only 'binary' and 'serializable' are supported as variable type.");
        }
      } else {
        variableType = RestResponseFactory.BYTE_ARRAY_VARIABLE_TYPE;
      }

      RestVariable.RestVariableScope scope = RestVariable.RestVariableScope.LOCAL;
      if (variableScope != null) {
        scope = RestVariable.getScopeFromString(variableScope);
      }

      if (variableType.equals(RestResponseFactory.BYTE_ARRAY_VARIABLE_TYPE)) {
        // Use raw bytes as variable value
        setVariable(
            execution, variableName, attachmentDataHolder.getAttachmentArray(), scope, isNew);

      } else {
        // Try deserializing the object
        InputStream inputStream =
            new ByteArrayInputStream(attachmentDataHolder.getAttachmentArray());
        ObjectInputStream stream = new ObjectInputStream(inputStream);
        Object value = stream.readObject();
        setVariable(execution, variableName, value, scope, isNew);
        stream.close();
      }

      if (responseVariableType == RestResponseFactory.VARIABLE_PROCESS) {
        return new RestResponseFactory()
            .createBinaryRestVariable(
                variableName,
                scope,
                variableType,
                null,
                null,
                execution.getId(),
                uriInfo.getBaseUri().toString());
      } else {
        return new RestResponseFactory()
            .createBinaryRestVariable(
                variableName,
                scope,
                variableType,
                null,
                execution.getId(),
                null,
                uriInfo.getBaseUri().toString());
      }

    } catch (IOException ioe) {
      throw new ActivitiIllegalArgumentException("Could not process multipart content", ioe);
    } catch (ClassNotFoundException ioe) {
      throw new BPMNContentNotSupportedException(
          "The provided body contains a serialized object for which the class is nog found: "
              + ioe.getMessage());
    }
  }