/* * This file is part of the Cerebro distribution. * (https://github.com/voyages-sncf-technologies/cerebro) * Copyright (C) 2017 VSCT. * * Cerebro is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, version 3 of the License. * * Cerebro is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.vsct.supervision.notification.service; import java.util.Objects; import java.util.Optional; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.vsct.supervision.notification.ErrorCode; import com.vsct.supervision.notification.exception.CerebroException; import com.vsct.supervision.notification.exception.DuplicateSubscriptionException; import com.vsct.supervision.notification.exception.SeyrenException; import com.vsct.supervision.notification.repository.SeyrenRepository; import com.vsct.supervision.seyren.api.Alarm; import com.vsct.supervision.seyren.api.Subscription; @Service public class SubscriptionService { private static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionService.class); @Autowired private SeyrenRepository seyrenRepository; /** * Get a subscription for a alarm. * * @param alarmId The ID of the alarm * @param subscriptionId The ID of the subscription to retrieve * @return The subscription retrieved */ public Subscription getSubscription(String alarmId, String subscriptionId) { Alarm c = seyrenRepository.getAlarm(alarmId); Subscription ret = c.getSubscriptions().stream().filter(s -> s.getId().equals(subscriptionId)).findAny().orElse(null); if (ret == null) { LOGGER.debug("Subscription {} for alarm {} does not exist.", subscriptionId, alarmId); throw new CerebroException(ErrorCode.SUBSCRIPTION_UNKNOWN, "Subscription " + subscriptionId + " for alarm " + alarmId + " does not exist."); } return ret; } /** * Add a new subscription to a alarm. * * If subscription already exist, throw an exception. * * @param subscription the subscription to add * @param alarmId the ID of the alarm to add subscription * @throws SeyrenException If add of subscription in Seyren fail (status code != 2xx) * @throws DuplicateSubscriptionException If subscription to add already exist */ public void addSubscription(Subscription subscription, String alarmId) { validateSubscription(subscription); if (this.searchSubscription(subscription, alarmId) != null) { LOGGER.debug("Identical subscription found (alarm id: {}).", alarmId); throw new DuplicateSubscriptionException("Attempting to add a subscription that already exists on alarm " + alarmId); } seyrenRepository.addSubscription(subscription, alarmId); } /** * Search a subscription in a alarm by these properties (from time, to time, days, etc.). * * @param subscription The subscription to search * @param alarmId ID of alarm look for subscription * @return subscription found, null if not found */ public Subscription searchSubscription(Subscription subscription, String alarmId) { LOGGER.debug("Searched identical subscription to: {}", subscription); Alarm alarm = seyrenRepository.getAlarm(alarmId); return alarm.getSubscriptions().stream().filter(s -> s.equals(subscription)).findAny().orElse(null); } /** * Update a subscription in Seyren (by subscription ID). * * <i>This method do nothing more than calling {@link SeyrenRepository#updateSubscription(Subscription, String)}</i> * * @param subscription The subscription to update * @param alarmId the ID of the alarm to update subscription */ public void updateSubscription(Subscription subscription, String alarmId) { Alarm alarm = seyrenRepository.getAlarm(alarmId); Optional<Subscription> actualSub = alarm.getSubscriptions().stream().filter(s -> s.getId().equals(subscription.getId())).findAny(); if (!actualSub.isPresent()) { throw new CerebroException(ErrorCode.SUBSCRIPTION_UNKNOWN, "The subscription passed as parameter does not exist in the Alarm " + alarmId); } validateUpdateSubscription(actualSub.get(), subscription); if (alarm.isEnabled()) { if (isLastSubscriptionActiveToDisable(actualSub.get(), subscription, alarm)) { alarm.setEnabled(false); seyrenRepository.updateAlarm(alarm); } } else if (!actualSub.get().isEnabled() && subscription.isEnabled()) { alarm.setEnabled(true); seyrenRepository.updateAlarm(alarm); } seyrenRepository.updateSubscription(subscription, alarmId); } private void validateSubscription(Subscription subscription) { if (!subscription.isFr() && !subscription.isMo() && !subscription.isSa() && !subscription.isSu() && !subscription.isTh() && !subscription.isTu() && !subscription.isWe()) { throw new CerebroException(ErrorCode.SUBSCRIPTION_INVALID, "No day selected to send alerts"); } if (StringUtils.isEmpty(subscription.getTarget())) { throw new CerebroException(ErrorCode.SUBSCRIPTION_INVALID, "No target for the subscription"); } } private void validateUpdateSubscription(Subscription current, Subscription updated) { validateSubscription(updated); if (!Objects.equals(current.getTarget(), updated.getTarget()) || !Objects.equals(current.getType(), updated.getType())) { throw new CerebroException(ErrorCode.SUBSCRIPTION_UPDATE_INVALID, "Fields 'target' and 'type' can not be updated"); } } private boolean isLastSubscriptionActiveToDisable(Subscription current, Subscription updated, Alarm alarm) { return current.isEnabled() && !updated.isEnabled() && !alarm.getSubscriptions().stream() .filter(s -> (!s.getId().equals(current.getId()) && s.isEnabled())).findAny().isPresent(); } /** * Remove a subscription to a alarm and the alarm if it have no more subscription. * * @param alarmId alarm ID to remove subscription * @param subscriptionId subscription ID to remove * @return String to indicate status of deletion and if alarm was deleted, see {@link SubscriptionService.DeletedSubscriptionStatus} * @see SubscriptionService.DeletedSubscriptionStatus */ public SubscriptionService.DeletedSubscriptionStatus deleteSubscription(String alarmId, String subscriptionId) { LOGGER.info("Delete subscription {} for alarm {}", subscriptionId, alarmId); if (this.seyrenRepository.deleteSubscription(alarmId, subscriptionId)) { Alarm alarm = seyrenRepository.getAlarm(alarmId); if (alarm.getSubscriptions().isEmpty()) { if (seyrenRepository.deleteAlarm(alarmId)) { return SubscriptionService.DeletedSubscriptionStatus.ALARM_DELETED; } throw new CerebroException(ErrorCode.SEYREN_ERROR, "Delete alarm '" + alarmId + "'has fail"); } return SubscriptionService.DeletedSubscriptionStatus.OK; } throw new CerebroException(ErrorCode.SUBSCRIPTION_DELETE_ERROR, "Delete subscription '" + subscriptionId + "' on alarm '" + alarmId + "' has fail"); } public enum DeletedSubscriptionStatus { OK, ALARM_DELETED; } }