/*
* 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.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.vsct.supervision.notification.model.Stat;
import com.vsct.supervision.notification.repository.SeyrenRepository;
import com.vsct.supervision.seyren.api.Alert;
import com.vsct.supervision.seyren.api.Alert.Alerts;
@Service
public class AlertService {
public static final int DEFAULT_NB_ITEMS_ALERTS = 20;
private static final int NB_ITEMS_GET_FOR_ALERTS = 50;
@Autowired
private SeyrenRepository seyrenRepository;
/**
* Get 20 first alerts from Seyren.
*
* @return Alert in Seyren
* @see SeyrenRepository#getAlerts(int, int)
*/
public Alert.Alerts getAlerts() {
return getAlerts(DEFAULT_NB_ITEMS_ALERTS, 0);
}
/**
* Get some alerts from Seyren.
*
* @param nbItem number of alert to retrieve
* @return All alarm in Seyren
* @see SeyrenRepository#getAlarmAlerts(String, int, int)
*/
public Alert.Alerts getAlerts(final int nbItem) {
return getAlerts(nbItem, 0);
}
/**
* Get some alerts from Seyren.
*
* <i>This method do nothing more than calling
* {@link SeyrenRepository#getAlerts(int, int)}</i>
*
* @param nbItem number of alert to retrieve
* @param start index of the fist traceResult
* @return Alert in Seyren
*/
public Alert.Alerts getAlerts(final int nbItem, final int start) {
return seyrenRepository.getAlerts(start, nbItem);
}
/**
* List alerts with no change.
*
* @param from time window to check alerts without change
* @return A stat object with each alarm ID and number of "no status change" in the desired time windows
*/
public List<Stat> getStatNoTypeChange(final String from) {
final Collection<Alert> alerts = this.getAlerts(from);
final Stat.StatBuilder stat = new Stat.StatBuilder();
for (final Alert a : alerts) {
if (a.getFromType() == a.getToType()) {
stat.increment(a.getAlarmId(), a.getToType());
} else {
stat.removeAndIgnore(a.getAlarmId());
}
}
return stat.build();
}
/**
* List alerts with change.
*
* @param from time window to check alerts with change
* @return A stat object with each alarm ID and number of status change in the desired time windows
*/
public List<Stat> getStatTypeChange(final String from) {
final Collection<Alert> alerts = this.getAlerts(from);
final Stat.StatBuilder stat = new Stat.StatBuilder();
for (final Alert a : alerts) {
if (a.getFromType() != a.getToType()) {
stat.increment(a.getAlarmId(), a.getToType());
}
}
return stat.build();
}
/**
* Get a precise history of alerts from Seyren.
*
* Use a "from" parameter e.g. "1d," "1h", etc.
*
* @param from from parameter to retrieve an history of a certain duration
* @return Alert of last hour, day, etc.
* @see AlertService#calcFromInstant(String)
*/
public Collection<Alert> getAlerts(final String from) {
final Instant limit = calcFromInstant(from);
boolean limitReached = false;
final Collection<Alert> result = new ArrayList<>();
int i = 0;
while (!limitReached && limit!=null) {
final Alert.Alerts alerts = getAlerts(NB_ITEMS_GET_FOR_ALERTS, i++ * NB_ITEMS_GET_FOR_ALERTS);
limitReached = olderThan(result, limit, alerts);
}
return result;
}
/**
* Get all alerts from alarms in seyren.
*
* <i>This method do nothing more than calling
* {@link SeyrenRepository#getAlarmAlerts(String, int, int)}</i>
*
* @param id
* Alarm ID to recover
* @return All alerts for this alarm with the key ID in Seyren
* @see SeyrenRepository#getAlarmAlerts(String, int, int)
*/
public Alert.Alerts getAlarmAlerts(final String id) {
return seyrenRepository.getAlarmAlerts(id, 0, DEFAULT_NB_ITEMS_ALERTS);
}
/**
* Add in collection all alerts older than a limit and return is the limit is reached.
*
* @param result [<b>this collection is edited in the method</b>] collection to store alerts older than limit
* @param limit the limit to reach
* @param alerts bucket of alerts to alarm
* @return true if one alert in bucket if older than limit, false otherwise
*/
private boolean olderThan(final Collection<Alert> result, final Instant limit, final Alerts alerts) {
for (final Alert a : alerts.getValues()) {
if (a.getTimestamp().isBefore(limit)) {
return true;
}
result.add(a);
}
return false;
}
/**
* Method to calc a from Instant with a e.g. "1d", "5h", etc.
*
* Can compute unit:
* - m
* - h
* - d
*
* @param from from parameter with unit
* @return An Instant, e.g. now minus 2 day with a from parameter = "2d"
*/
private Instant calcFromInstant(final String from) {
Instant result = null;
if (from.contains("m")) {
final int nb = Integer.valueOf(from.replace("m", ""));
result = Instant.now().minus(nb, ChronoUnit.MINUTES);
}
if (from.contains("d")) {
final int nb = Integer.valueOf(from.replace("d", ""));
result = Instant.now().minus(nb, ChronoUnit.DAYS);
}
if (from.contains("h")) {
final int nb = Integer.valueOf(from.replace("h", ""));
result = Instant.now().minus(nb, ChronoUnit.HOURS);
}
return result;
}
}