/*
* 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.controller;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.vsct.supervision.notification.exception.CerebroException;
import com.vsct.supervision.notification.log.Loggable;
import com.vsct.supervision.notification.model.AlarmMapper;
import com.vsct.supervision.notification.model.CerebroAlarm;
import com.vsct.supervision.notification.model.GraphiteSources;
import com.vsct.supervision.notification.model.Stat;
import com.vsct.supervision.notification.model.SubscriptionMapper;
import com.vsct.supervision.notification.service.AlarmService;
import com.vsct.supervision.notification.service.AlertService;
import com.vsct.supervision.notification.service.SubscriptionService;
import com.vsct.supervision.seyren.api.Alarm;
import com.vsct.supervision.seyren.api.Alert;
import com.vsct.supervision.seyren.api.Subscription;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
@CrossOrigin(methods = { RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PUT })
@RestController
@Loggable(service = "cerebro")
public class CerebroController {
private static final Logger LOGGER = LoggerFactory.getLogger(CerebroController.class);
@Autowired
private AlarmService alarmService;
@Autowired
private SubscriptionService subscriptionService;
@Autowired
private AlertService alertService;
@Autowired
private GraphiteSources graphiteSources;
@Autowired
private AlarmMapper alarmMapper;
@Autowired
private SubscriptionMapper subscriptionMapper;
//SOURCES
@RequestMapping(value="/datasources/locations", method = RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=200, message = "Returns the datasource backend location(s)")})
public Collection<URI> sources() {
return graphiteSources.getIpportsByUrl().keySet();
}
//ALARMS
@RequestMapping(value="/alarms", method = RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=200, message = "Returns the subscriber's alarms, or all alarms if no email is provided")})
public Collection<Alarm> all(@ApiParam(name="subscriptionTarget", value="a subscriber's email") @RequestParam(name = "subscriptionTarget", required = false) final String subTarget) {
final Collection<Alarm> alarms = alarmMapper.mapToPresentation(subTarget != null ? alarmService.searchAlarmsBySubscriptionTarget(subTarget) : alarmService.getAllAlarms());
return alarms;
}
@RequestMapping(value="/alarms/{id}", method = RequestMethod.GET)
public CerebroAlarm getAlarm(@ApiParam(name="id", value="an alarm Id", required = true) @PathVariable("id") final String id) {
return new CerebroAlarm(alarmMapper.mapToPresentation(alarmService.getAlarm(id)));
}
@RequestMapping(value = "/alarms", method = RequestMethod.POST)
@ApiResponses(value={@ApiResponse(code=200, message = "Creates a new alarm and returns its Id")})
public String addAlarm(@ApiParam(name="alarm", value="an alarm to add", required = true) @RequestBody final Alarm alarm) {
return alarmService.subscribeToAAlarm(alarmMapper.mapNewAlarmFormToSeyren(alarm)).getId();
}
@RequestMapping(value = "/alarms/{alarmId}/subscriptions/{subscriptionId}", method = RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=200, message = "Returns the subscription with the given alarm and subscription Ids")})
public Subscription getSubscription(@ApiParam(name="alarmId", value="an alarm Id") @PathVariable("alarmId") final String alarmId,
@ApiParam(name = "subscriptionId", value = "a subscription Id") @PathVariable("subscriptionId") final String subscriptionId) {
return subscriptionService.getSubscription(alarmId, subscriptionId);
}
@RequestMapping(value = "/alarms/search", method = RequestMethod.POST)
@ApiResponses(value={@ApiResponse(code=200, message = "search for an alarm")})
public Alarm searchAlarm(@ApiParam(name="alarm", value="the alarm to search") @RequestBody final Alarm alarm) {
return alarmMapper.mapToPresentation(alarmService.searchAlarm(alarmMapper.mapNewAlarmFormToSeyren(alarm)));
}
@RequestMapping(value = "/alarms", method = RequestMethod.PUT)
@ApiResponses(value={@ApiResponse(code=200, message = "Updates the alarm and returns its Id")})
public String updateAlarm(@ApiParam(name="alarm", value="an updated alarm", required = true) @RequestBody final Alarm alarm) {
return alarmService.updateAlarm(alarmMapper.mapUpdateAlarmFormToSeyren(alarm)).getId();
}
//SUBSCRIPTIONS
@RequestMapping(value = "/alarms/{alarmId}/subscriptions", method = RequestMethod.POST)
@ApiResponses(value={@ApiResponse(code=200, message = "Adds a subscription to an alarm")})
public void addSubscription(@ApiParam(name="subscription", value="a subscription to add") @RequestBody final Subscription subscription,
@ApiParam(name="alarmId", value="the Id of the alarm") @PathVariable final String alarmId) {
subscriptionService.addSubscription(subscriptionMapper.mapNewSubscriptionFormToSeyren(subscription), alarmId);
}
@RequestMapping(value = "/alarms/{alarmId}/subscriptions/{subscriptionId}", method = RequestMethod.DELETE)
@ApiResponses(value={@ApiResponse(code=200, message = "Deletes the subscription with the given alarm and subscription Ids")})
public String deleteSubscription(@ApiParam(name="alarmId", value="an alarm Id") @PathVariable("alarmId") final String alarmId,
@ApiParam(name = "subscriptionId", value = "a subscription Id") @PathVariable("subscriptionId") final String subscriptionId) {
return subscriptionService.deleteSubscription(alarmId, subscriptionId).name();
}
@RequestMapping(value = "/alarms/{alarmId}/subscriptions/search", method = RequestMethod.POST)
@ApiResponses(value={@ApiResponse(code=200, message = "Search for a subscription")})
public Subscription searchSubscription(@ApiParam(name="subscription", value="the subscription to search for") @RequestBody final Subscription subscription,
@ApiParam(name="alarmId") @PathVariable final String alarmId) {
return subscriptionService.searchSubscription(subscription, alarmId);
}
@RequestMapping(value = "/alarms/{alarmId}/subscriptions/{subscriptionId}", method = RequestMethod.PUT)
@ApiResponses(value={@ApiResponse(code=200, message = "Updates a subscription")})
public void updateSubscription(@ApiParam(name="subscription", value="the updated subscription") @RequestBody final Subscription subscription,
@ApiParam(name="alarmId", value="the Id of the alarm to which the subscription is linked") @PathVariable("alarmId") final String alarmId) {
subscriptionService.updateSubscription(subscriptionMapper.mapUpdateSubscriptionFormToSeyren(subscription), alarmId);
}
//ALERTS
@RequestMapping(value="/alerts", method = RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=200, message = "Returns the latest alarm alerts")})
public Collection<Alert> getAlerts(@ApiParam(name="nbItem", value="number of alerts to return") @RequestParam(value = "items", required = false, defaultValue = "20") final int nbItem,
@ApiParam(name="start", value="starting date") @RequestParam(value = "start", required = false, defaultValue = "0") final int start,
@ApiParam(name="from") @RequestParam(value = "from", required = false) final String from) {
Collection<Alert> alerts;
if (from != null) {
alerts = alertService.getAlerts(from);
} else {
alerts = alertService.getAlerts(nbItem, start).getValues();
}
return alerts;
}
@RequestMapping(value="/alerts/stats/nochanges", method = RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=200, message = "Returns stats (number of occurrence,current status) about all alerts without status change from \"from\" to now")})
public List<Stat> getAlertStatNoTypeChange(@ApiParam(name="from", value="beginning date") @RequestParam("from") final String from) {
final List<Stat> stat = alertService.getStatNoTypeChange(from);
return stat;
}
@RequestMapping("/alerts/stats/changes")
@ApiResponses(value={@ApiResponse(code=200, message = "Returns stats (number of occurrence, current status) about all alerts with status change from \"from\" to now")})
public List<Stat> getAlertStatTypeChange(@RequestParam("from") final String from) {
final List<Stat> stat = alertService.getStatTypeChange(from);
return stat;
}
@RequestMapping(value="/alarms/{id}/alerts", method = RequestMethod.GET)
@ApiResponses(value={@ApiResponse(code=200, message = "Returns all alerts for a given alarm")})
public Collection<Alert> getAlarmAlerts(@ApiParam(name="id", value="an alarm Id") @PathVariable("id") final String id) {
final Collection<Alert> alerts = alertService.getAlarmAlerts(id).getValues();
return alerts;
}
//ERRORS
@ExceptionHandler(CerebroException.class)
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public String getErrorCode(final CerebroException exception) throws IOException {
LOGGER.error("Service error", exception);
ObjectMapper objectMapper = new ObjectMapper();
FilterProvider filterProvider = new SimpleFilterProvider().addFilter("responseFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("errorCode", "errorMessage"));
objectMapper.setFilterProvider(filterProvider);
return objectMapper.writeValueAsString(exception);
}
}