@POST
  @Timed
  @Produces(MediaType.APPLICATION_JSON)
  @Path("applications")
  @ApiOperation(
      "Adds new application to SeaClouds Platform based on a SeaClouds-compliant TOSCA DAM specification")
  public Response addApplication(@ApiParam() String dam) {
    SeaCloudsApplicationData seaCloudsApplication = null;

    if (dam == null) {
      LOG.error("Missing input parameters");
      return Response.status(Response.Status.NOT_ACCEPTABLE).build();
    } else {
      try {
        LOG.debug("Deploy new application process started");

        seaCloudsApplication = new SeaCloudsApplicationData(dam);

        LOG.debug("STEP 1: Start deployment of the application");
        TaskSummary taskSummary = deployer.deployApplication(dam);
        seaCloudsApplication.setDeployerApplicationId(taskSummary);

        if (seaCloudsApplication.getMonitoringRulesTemplateId() != null) {
          LOG.debug("STEP 2: Retrieve Monitoring Rules from TOSCA");
          MonitoringRules monitoringRules =
              planner.getMonitoringRulesByTemplateId(
                  seaCloudsApplication.getMonitoringRulesTemplateId());

          LOG.debug("STEP 3: Install Monitoring Rules");
          monitor.addMonitoringRules(monitoringRules);
          seaCloudsApplication.setMonitoringRulesIds(monitoringRules);
        }

        if (seaCloudsApplication.getAgreementTemplateId() != null) {
          LOG.debug("STEP 4: Retrieve SLA Agreements from TOSCA");
          Agreement agreement =
              sla.getAgreementByTemplateId(seaCloudsApplication.getAgreementTemplateId());

          LOG.debug("STEP 5: Install SLA Agreements");
          sla.addAgreement(agreement);
          seaCloudsApplication.setAgreementId(agreement);

          LOG.debug("STEP 6: Notify Rules Ready (Issue #56)");
          sla.notifyRulesReady(agreement);
        }

        LOG.debug("Application deployment process finished");
        dataStore.addSeaCloudsApplicationData(seaCloudsApplication);
        return Response.ok(seaCloudsApplication).build();
      } catch (Exception e) {
        cleanUpApplicationDependencies(seaCloudsApplication);
        LOG.error(e.getMessage());
        return Response.status(Response.Status.BAD_REQUEST).build();
      }
    }
  }
  private void cleanUpApplicationDependencies(SeaCloudsApplicationData seaCloudsApplicationData) {

    // TODO: Undo observers (Maybe they are removed when MR are removed)

    // TODO: Undo grafana

    if (seaCloudsApplicationData.getMonitoringRulesTemplateId() != null) {
      try {
        for (String ruleId : seaCloudsApplicationData.getMonitoringRulesIds()) {
          monitor.removeMonitoringRule(ruleId);
        }
      } catch (Exception e) {
        LOG.debug("Something went wrong during the cleanup of the monitoring rules");
        // This is perfectly fine, it will happen if this phase was not reached before the error.
      }
    }
    if (seaCloudsApplicationData.getAgreementId() != null) {
      try {
        sla.removeAgreement(seaCloudsApplicationData.getAgreementId());
      } catch (Exception e) {
        LOG.debug("Something went wrong during the cleanup of the agreement");
        // This is perfectly fine, it will happen if this phase was not reached before the error.
      }
    }
    try {
      deployer.removeApplication(seaCloudsApplicationData.getDeployerApplicationId());
    } catch (Exception e) {
      LOG.debug("Something went wrong during the cleanup of the application");
      // This is perfectly fine, it will happen if this phase was not reached before the error.
    }
  }
  @GET
  @Timed
  @Produces(MediaType.APPLICATION_JSON)
  @Path("applications")
  @ApiOperation(value = "List all SeaClouds deployed Applications")
  public Response listApplications() throws IOException {
    List<SeaCloudsApplicationData> applications = dataStore.listSeaCloudsApplicationData();

    for (SeaCloudsApplicationData application : applications) {
      ApplicationSummary applicationSummary =
          deployer.getApplication(application.getDeployerApplicationId());
      application.setDeploymentStatus(applicationSummary.getStatus());

      if (application.getAgreementId() != null) {
        GuaranteeTermsStatus agreementStatus = sla.getAgreementStatus(application.getAgreementId());
        application.setAgreementStatus(
            IGuaranteeTerm.GuaranteeTermStatusEnum.valueOf(agreementStatus.getValue()));
      }
    }
    return Response.ok(applications).build();
  }