public void setRuleStartTime(
      final ProcessInstanceIdentifier identifier, final String ruleFlowGroup, final String nodeId) {
    // Create the rule (one for each call).
    final MeasuredRule rule = em.merge(new MeasuredRule(identifier, ruleFlowGroup, nodeId));

    // Add it to the corresponding process instance.
    final MeasuredProcessInstance processInstance = findProcessInstance(identifier);
    if (processInstance == null) {
      throw new IllegalStateException(
          "Rule started for process instance [" + identifier + "], which cannot be found.");
    }
    processInstance.addRule(rule);

    // Set the time.
    rule.setStartingTime(new Date());
  }
  private ProcessRuntimeMetrics getRuntimeMetrics(final ProcessIdentifier identifier) {
    final CriteriaBuilder cb = em.getCriteriaBuilder();
    final CriteriaQuery<MeasuredProcessInstance> cq = cb.createQuery(MeasuredProcessInstance.class);
    final Root<MeasuredProcessInstance> processInstanceRoot =
        cq.from(MeasuredProcessInstance.class);
    cq.where(
        cb.equal(
            processInstanceRoot
                .get(MeasuredProcessInstance_.identifier)
                .get(ProcessInstanceIdentifier_.metricsId),
            identifier.getMetricsId()),
        cb.equal(
            processInstanceRoot
                .get(MeasuredProcessInstance_.identifier)
                .get(ProcessInstanceIdentifier_.packageName),
            identifier.getPackageName()),
        cb.equal(
            processInstanceRoot
                .get(MeasuredProcessInstance_.identifier)
                .get(ProcessInstanceIdentifier_.processId),
            identifier.getProcessId()));
    final List<MeasuredProcessInstance> instances = em.createQuery(cq).getResultList();

    final ProcessRuntimeMetrics metrics = new ProcessRuntimeMetrics();
    long totalRuntime = 0L;
    for (final MeasuredProcessInstance instance : instances) {
      if (instance.getTimeToComplete() == null) {
        continue;
      }
      final long runtime = instance.getTimeToComplete().longValue();
      totalRuntime += runtime;
      if ((metrics.getMinRuntime() == 0) || (metrics.getMinRuntime() > runtime)) {
        metrics.setMinRuntime(runtime);
      }
      if ((metrics.getMaxRuntime() == 0) || (metrics.getMaxRuntime() < runtime)) {
        metrics.setMaxRuntime(runtime);
      }
    }
    final long totalInstances = instances.size();
    metrics.setNumberOfInstances(totalInstances);
    if (totalInstances != 0) {
      metrics.setMeanRuntime(totalRuntime / totalInstances);
    } else {
      metrics.setMeanRuntime(0);
    }
    return metrics;
  }
  public void setHumanTaskStartTime(
      final ProcessInstanceIdentifier identifier,
      final String taskName,
      final String groupId,
      final String nodeId) {
    // Create the task (one for each call).
    final MeasuredHumanTask task =
        em.merge(new MeasuredHumanTask(identifier, taskName, groupId, nodeId));

    // Add it to the corresponding process instance.
    final MeasuredProcessInstance processInstance = findProcessInstance(identifier);
    if (processInstance == null) {
      throw new IllegalStateException(
          "Human Task started for process instance [" + identifier + "], which cannot be found.");
    }
    processInstance.addHumanTask(task);

    // Set the time.
    task.setStartingTime(new Date());
  }
  /**
   * Set the time at which a process instance starts.
   *
   * @param identifier Data to uniquely identify the process instance.
   */
  public void setProcessInstanceStartTime(final ProcessInstanceIdentifier identifier) {
    // First event, so create the instance.
    final MeasuredProcessInstance processInstance =
        em.merge(new MeasuredProcessInstance(identifier));

    // Add it to the originating definition.
    synchronized (
        LOCK) { // Synchronized because concurrent instances will cause locking exceptions.
      final MeasuredProcess process = findProcess(identifier.toProcessIdentifier());
      if (process == null) {
        throw new IllegalStateException(
            "Instance started for process ["
                + identifier.toProcessIdentifier()
                + "], which cannot be found.");
      }
      process.addInstance(processInstance);
      em.flush();
    }

    // Set the time.
    processInstance.setStartingTime(new Date());
  }