/**
  * Find a {@link MeasuredProcessInstance}.
  *
  * @param identifier The data to uniquely identify a process.
  * @return The intended process instance, or <code>null</code> if it was not available.
  */
 public MeasuredProcessInstance findProcessInstance(final ProcessInstanceIdentifier 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()),
       cb.equal(
           processInstanceRoot
               .get(MeasuredProcessInstance_.identifier)
               .get(ProcessInstanceIdentifier_.ksessionId),
           identifier.getKsessionId()),
       cb.equal(
           processInstanceRoot
               .get(MeasuredProcessInstance_.identifier)
               .get(ProcessInstanceIdentifier_.processInstanceId),
           identifier.getProcessInstanceId()));
   MeasuredProcessInstance processInstance = null;
   try {
     processInstance = em.createQuery(cq).getSingleResult();
   } catch (final NoResultException nrEx) {
     // Leave NULL, wasn't available.
   } catch (final NonUniqueResultException nurEx) {
     log.error(
         "Multiple process instances with identity " + identifier + " found, unexpectedly.",
         nurEx);
   }
   return processInstance;
 }
  /**
   * 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());
  }
 /**
  * Find a {@link MeasuredHumanTask}.
  *
  * @param identifier Data to uniquely identify a process instance.
  * @param taskName The name of the required task.
  * @param nodeId The unique ID of the Human Task node this task was called for.
  * @return The intended task, or <code>null</code> if it was not available.
  */
 public MeasuredHumanTask findHumanTask(
     final ProcessInstanceIdentifier identifier, final String taskName, final String nodeId) {
   final CriteriaBuilder cb = em.getCriteriaBuilder();
   final CriteriaQuery<MeasuredHumanTask> cq = cb.createQuery(MeasuredHumanTask.class);
   final Root<MeasuredHumanTask> taskRoot = cq.from(MeasuredHumanTask.class);
   cq.where(
       cb.equal(
           taskRoot.get(MeasuredHumanTask_.identifier).get(ProcessInstanceIdentifier_.metricsId),
           identifier.getMetricsId()),
       cb.equal(
           taskRoot.get(MeasuredHumanTask_.identifier).get(ProcessInstanceIdentifier_.packageName),
           identifier.getPackageName()),
       cb.equal(
           taskRoot.get(MeasuredHumanTask_.identifier).get(ProcessInstanceIdentifier_.processId),
           identifier.getProcessId()),
       cb.equal(
           taskRoot.get(MeasuredHumanTask_.identifier).get(ProcessInstanceIdentifier_.ksessionId),
           identifier.getKsessionId()),
       cb.equal(
           taskRoot
               .get(MeasuredHumanTask_.identifier)
               .get(ProcessInstanceIdentifier_.processInstanceId),
           identifier.getProcessInstanceId()),
       cb.equal(taskRoot.get(MeasuredHumanTask_.taskName), taskName),
       cb.equal(taskRoot.get(MeasuredHumanTask_.nodeId), nodeId));
   MeasuredHumanTask task = null;
   try {
     task = em.createQuery(cq).getSingleResult();
   } catch (final NoResultException nrEx) {
     // Leave NULL, wasn't available.
   } catch (final NonUniqueResultException nurEx) {
     log.error(
         "Multiple Human Tasks with ID " + taskName + " under one Metrics found, unexpectedly.",
         nurEx);
   }
   return task;
 }
 /**
  * Find a {@link MeasuredRule}.
  *
  * @param identifier Data to uniquely identify a process instance.
  * @param ruleFlowGroup The group ID of the required rule.
  * @param nodeId The unique ID of the Rule node this rule was called for.
  * @return The intended rule, or <code>null</code> if it was not available.
  */
 public MeasuredRule findRule(
     final ProcessInstanceIdentifier identifier, final String ruleFlowGroup, final String nodeId) {
   final CriteriaBuilder cb = em.getCriteriaBuilder();
   final CriteriaQuery<MeasuredRule> cq = cb.createQuery(MeasuredRule.class);
   final Root<MeasuredRule> ruleRoot = cq.from(MeasuredRule.class);
   cq.where(
       cb.equal(
           ruleRoot.get(MeasuredRule_.identifier).get(ProcessInstanceIdentifier_.metricsId),
           identifier.getMetricsId()),
       cb.equal(
           ruleRoot.get(MeasuredRule_.identifier).get(ProcessInstanceIdentifier_.packageName),
           identifier.getPackageName()),
       cb.equal(
           ruleRoot.get(MeasuredRule_.identifier).get(ProcessInstanceIdentifier_.processId),
           identifier.getProcessId()),
       cb.equal(
           ruleRoot.get(MeasuredRule_.identifier).get(ProcessInstanceIdentifier_.ksessionId),
           identifier.getKsessionId()),
       cb.equal(
           ruleRoot
               .get(MeasuredRule_.identifier)
               .get(ProcessInstanceIdentifier_.processInstanceId),
           identifier.getProcessInstanceId()),
       cb.equal(ruleRoot.get(MeasuredRule_.ruleFlowGroup), ruleFlowGroup),
       cb.equal(ruleRoot.get(MeasuredRule_.nodeId), nodeId));
   MeasuredRule rule = null;
   try {
     rule = em.createQuery(cq).getSingleResult();
   } catch (final NoResultException nrEx) {
     // Leave NULL, wasn't available.
   } catch (final NonUniqueResultException nurEx) {
     log.error(
         "Multiple rules with ID " + ruleFlowGroup + " under one Metrics found, unexpectedly.",
         nurEx);
   }
   return rule;
 }