@Override
 @Secured
 public Value addValue(Value value) throws ServiceException {
   TestExecution exec = testExecutionDAO.get(value.getTestExecution().getId());
   if (exec == null) {
     throw new ServiceException(
         "serviceException.addValue.testExecutionNotFound", value.getTestExecution().getName());
   }
   Metric metric = null;
   if (value.getMetric().getId() != null) {
     metric = metricDAO.get(value.getMetric().getId());
   } else {
     List<Metric> metrics =
         metricDAO.getMetricByNameAndGroup(
             value.getMetric().getName(), exec.getTest().getGroupId());
     if (metrics.size() > 0) {
       metric = metricDAO.get(metrics.get(0).getId());
     }
   }
   if (metric == null) {
     throw new ServiceException("serviceException.metricNotFound", value.getMetric().getName());
   }
   value.setTestExecution(exec);
   value.setMetric(metric);
   // check if other values for given metric exist, if yes, we can only add one if both old and new
   // one have at least one parameter
   List<Value> existingValuesForMetric = valueDAO.find(exec.getId(), metric.getId());
   if (!existingValuesForMetric.isEmpty()) {
     for (Value v : existingValuesForMetric) {
       if (!v.hasParameters()) {
         throw new ServiceException("serviceException.unparametrizedMultiValue");
       }
     }
     if (!value.hasParameters()) {
       throw new ServiceException("serviceException.unparametrizedMultiValue");
     }
   }
   Value freshValue = valueDAO.create(value);
   Value freshValueClone = freshValue.clone();
   List<ValueParameter> newParams = new ArrayList<ValueParameter>();
   if (value.hasParameters()) {
     for (ValueParameter valueParameter : value.getParameters()) {
       valueParameter.setValue(freshValue);
       newParams.add(valueParameterDAO.create(valueParameter).clone());
       newParams.get(newParams.size() - 1).setValue(freshValueClone);
     }
   }
   freshValueClone.setParameters(newParams.isEmpty() ? null : newParams);
   return freshValueClone;
 }
 @Override
 @Secured
 public Value updateValue(Value value) throws ServiceException {
   TestExecution exec = testExecutionDAO.get(value.getTestExecution().getId());
   if (exec == null) {
     throw new ServiceException(
         "serviceException.updateValue.testExecutionNotFound", value.getTestExecution().getName());
   }
   Value oldValue = valueDAO.get(value.getId());
   if (oldValue == null) {
     throw new ServiceException("serviceException.valueNotFound");
   }
   Value freshValue = valueDAO.update(value);
   Value freshValueClone = freshValue.clone();
   freshValueClone.setMetric(freshValue.getMetric().clone());
   freshValueClone.getMetric().setValues(null);
   UpdateSet<ValueParameter> updateSet =
       EntityUtils.updateSet(oldValue.getParameters(), value.getParameters());
   if (!updateSet.removed.isEmpty()) {
     throw new ServiceException("serviceException.staleCollection");
   }
   List<ValueParameter> newParams = new ArrayList<ValueParameter>();
   for (ValueParameter vp : updateSet.toAdd) {
     vp.setValue(freshValue);
     newParams.add(valueParameterDAO.create(vp).clone());
     newParams.get(newParams.size() - 1).setValue(freshValueClone);
   }
   for (ValueParameter vp : updateSet.toUpdate) {
     newParams.add(valueParameterDAO.update(vp).clone());
     newParams.get(newParams.size() - 1).setValue(freshValueClone);
   }
   for (ValueParameter vp : updateSet.toRemove) {
     valueParameterDAO.remove(vp);
   }
   freshValueClone.setParameters(newParams.isEmpty() ? null : newParams);
   return freshValueClone;
 }
  @Override
  @Secured
  public TestExecution createTestExecution(TestExecution testExecution) throws ServiceException {
    // The test referred by test execution has to be an existing test
    Test test = testDAO.get(testExecution.getTest().getId());
    testExecution.setTest(test);
    TestExecution storedTestExecution = testExecutionDAO.create(testExecution);
    // execution params
    if (testExecution.getParameters() != null && testExecution.getParameters().size() > 0) {
      for (TestExecutionParameter param : testExecution.getParameters()) {
        param.setTestExecution(storedTestExecution);
        testExecutionParameterDAO.create(param);
      }
    }
    // tags
    if (testExecution.getTags() != null && testExecution.getTags().size() > 0) {
      for (Tag teg : testExecution.getTags()) {
        Tag tag = tagDAO.findByName(teg.getName());
        if (tag == null) {
          tag = tagDAO.create(teg);
        }

        Collection<TestExecution> tagTestExecutions = tag.getTestExecutions();
        if (tagTestExecutions == null) {
          tag.setTestExecutions(new ArrayList<>());
        }

        tag.getTestExecutions().add(storedTestExecution);
      }
    }
    // values
    if (testExecution.getValues() != null && !testExecution.getValues().isEmpty()) {
      for (Value value : testExecution.getValues()) {
        value.setTestExecution(storedTestExecution);
        if (value.getMetricName() == null) {
          throw new IllegalArgumentException("Metric name is mandatory");
        }
        Metric metric =
            test.getMetrics()
                .stream()
                .filter(m -> m.getName().equals(value.getMetricName()))
                .findFirst()
                .get();
        if (metric == null) {
          throw new ServiceException(
              "serviceException.metricNotInTest",
              test.getName(),
              test.getId().toString(),
              value.getMetricName());
        }
        value.setMetric(metric);
        valueDAO.create(value);
        if (value.getParameters() != null && value.getParameters().size() > 0) {
          for (ValueParameter vp : value.getParameters()) {
            vp.setValue(value);
            valueParameterDAO.create(vp);
          }
        }
      }
    }

    TestExecution clone = cloneAndFetch(storedTestExecution, true, true, true, true, true);
    log.debug("Created new test execution " + clone.getId());

    alertingService.processAlerts(clone);

    return clone;
  }