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);
      }
    }
  }
  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 RestVariable setSimpleVariable(
      RestVariable restVariable, Execution execution, boolean isNew, UriInfo uriInfo) {
    if (restVariable.getName() == null) {
      throw new ActivitiIllegalArgumentException("Variable name is required");
    }

    // Figure out scope, revert to local is omitted
    RestVariable.RestVariableScope scope = restVariable.getVariableScope();
    if (scope == null) {
      scope = RestVariable.RestVariableScope.LOCAL;
    }

    Object actualVariableValue = new RestResponseFactory().getVariableValue(restVariable);
    setVariable(execution, restVariable.getName(), actualVariableValue, scope, isNew);

    return constructRestVariable(
        restVariable.getName(), restVariable.getValue(), scope, execution.getId(), false, uriInfo);
  }
  public RestVariable getVariableFromRequest(
      Execution execution,
      String variableName,
      String scope,
      boolean includeBinary,
      UriInfo uriInfo) {

    boolean variableFound = false;
    Object value = null;

    if (execution == null) {
      throw new ActivitiObjectNotFoundException("Could not find an execution", Execution.class);
    }
    RuntimeService runtimeService = BPMNOSGIService.getRumtimeService();
    RestVariable.RestVariableScope variableScope = RestVariable.getScopeFromString(scope);
    if (variableScope == null) {
      // First, check local variables (which have precedence when no scope is supplied)
      if (runtimeService.hasVariableLocal(execution.getId(), variableName)) {
        value = runtimeService.getVariableLocal(execution.getId(), variableName);
        variableScope = RestVariable.RestVariableScope.LOCAL;
        variableFound = true;
      } else {
        if (execution.getParentId() != null) {
          value = runtimeService.getVariable(execution.getParentId(), variableName);
          variableScope = RestVariable.RestVariableScope.GLOBAL;
          variableFound = true;
        }
      }
    } else if (variableScope == RestVariable.RestVariableScope.GLOBAL) {
      // Use parent to get variables
      if (execution.getParentId() != null) {
        value = runtimeService.getVariable(execution.getParentId(), variableName);
        variableScope = RestVariable.RestVariableScope.GLOBAL;
        variableFound = true;
      }
    } else if (variableScope == RestVariable.RestVariableScope.LOCAL) {

      value = runtimeService.getVariableLocal(execution.getId(), variableName);
      variableScope = RestVariable.RestVariableScope.LOCAL;
      variableFound = true;
    }

    if (!variableFound) {
      throw new ActivitiObjectNotFoundException(
          "Execution '"
              + execution.getId()
              + "' doesn't have a variable with name: '"
              + variableName
              + "'.",
          VariableInstanceEntity.class);
    } else {
      return constructRestVariable(
          variableName, value, variableScope, execution.getId(), includeBinary, uriInfo);
    }
  }
  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 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 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());
    }
  }