package com.romeh.ignitemanager.repositories.impl; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import javax.cache.Cache; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cache.query.SqlQuery; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import com.romeh.ignitemanager.entities.AlertConfigEntry; import com.romeh.ignitemanager.entities.AlertEntry; import com.romeh.ignitemanager.entities.CacheNames; import com.romeh.ignitemanager.exception.ResourceNotFoundException; import com.romeh.ignitemanager.repositories.AlertsConfigStore; import com.romeh.ignitemanager.repositories.AlertsStore; import com.romeh.ignitemanager.services.MailService; @Component public class IgniteAlertsStore implements AlertsStore { private static final Logger logger = LoggerFactory.getLogger(IgniteAlertsStore.class); @Autowired private Ignite ignite; @Autowired private MailService mailService; @Autowired private AlertsConfigStore alertsConfigStore; @Override public List<AlertEntry> getAlertForServiceId(String serviceId) { final String sql = "serviceId = ?"; SqlQuery<String, AlertEntry> query = new SqlQuery<>(AlertEntry.class, sql); query.setArgs(serviceId); return Optional.ofNullable(getAlertsCache().query(query).getAll() .stream() .map(Cache.Entry::getValue) .collect(Collectors.toList())) .orElseThrow(() -> new ResourceNotFoundException(String.format("Alert for %s not found", serviceId))); } @Override public void updateAlertEntry(String serviceId, String serviceCode, AlertEntry alertEntry) { final IgniteCache<String, AlertEntry> alertsCache = getAlertsCache(); // update the alert entry via cache invoke for atomicity alertsCache.invoke(alertEntry.getAlertId(), (mutableEntry, objects) -> { if (mutableEntry.exists() && mutableEntry.getValue() != null) { logger.debug("updating alert entry into the cache store invoke: {},{}", serviceId, serviceCode); mutableEntry.setValue(alertEntry); } else { throw new ResourceNotFoundException(String.format("Alert for %s with %s not found", serviceId, serviceCode)); } // by api design nothing needed here return null; }); } @Override public List<AlertEntry> getAllAlerts() { final String sql = "select * from AlertEntry"; SqlQuery<String, AlertEntry> query = new SqlQuery<>(AlertEntry.class, sql); return getAlertsCache().query(query).getAll() .stream() .map(Cache.Entry::getValue) .collect(Collectors.toList()); } @Override public void deleteAlertEntry(String alertId) { final IgniteCache<String, AlertEntry> alertsCache = getAlertsCache(); alertsCache.remove(alertId); } @Override public void createAlertEntry(AlertEntry alertEntry) { // get the alert config if any final Optional<AlertConfigEntry> configForServiceIdCodeIdCount = alertsConfigStore.getConfigForServiceIdCodeIdCount(alertEntry.getServiceId(), alertEntry.getErrorCode()); // get the max count of alerts before sending mail final int maxCount = configForServiceIdCodeIdCount.isPresent() ? configForServiceIdCodeIdCount.get().getMaxCount() : 1; final String mailTemplate = configForServiceIdCodeIdCount.isPresent() ? configForServiceIdCodeIdCount.get().getMailTemplate() : "ticket"; // define the expiry of the entry in the cache final IgniteCache<String, AlertEntry> alertsCache = getAlertsCache(); // insert into the key value store alertsCache.put(alertEntry.getAlertId(), alertEntry); // send the mail notification if max is there final SqlFieldsQuery sql = new SqlFieldsQuery("select count(*) from AlertEntry where serviceId = '" + alertEntry.getServiceId() + "' and errorCode = '" + alertEntry.getErrorCode() + "'"); final List<List<?>> count = alertsCache.query(sql).getAll(); if (count != null && !count.isEmpty()) { final Long result = (Long) count.get(0).get(0); if (result >= maxCount) { logger.debug("max alerts count is reached for : {}, start sending mail alert {}", alertEntry.toString()); sendMail(alertEntry, configForServiceIdCodeIdCount.isPresent() ? configForServiceIdCodeIdCount.get().getEmails() : Collections.emptyList(), mailTemplate); } } } @Async protected void sendMail(AlertEntry alertEntry, List<String> emails, String mailTemplate) { // send the mail then delete the entry final boolean doneSending = mailService.sendAlert(alertEntry, emails, mailTemplate); if (doneSending) { cleanAllAlertEntriesForThatErrorCodeAndServiceCode(alertEntry.getServiceId(), alertEntry.getErrorCode()); } } // clean all alerts for that service code and service id private void cleanAllAlertEntriesForThatErrorCodeAndServiceCode(String serviceId, String errorId) { // commenting it out for testing without clean-up /* // query the matching records first final String sql = "serviceId = ? and errorCode= ?"; SqlQuery<String,AlertEntry> query = new SqlQuery(AlertEntry.class,sql); query.setArgs(serviceId, errorId); final List<Cache.Entry<String, AlertEntry>> to_Delete_Alerts = getAlertsCache().query(query).getAll(); // then call remove all as this will remove the records from the cache and the persistent file system // as sql delete will just delete it from the cache layer not the file system // or the persistent store if(to_Delete_Alerts!=null && !to_Delete_Alerts.isEmpty()){ getAlertsCache().removeAll(new HashSet(to_Delete_Alerts.stream().map(stringAlertEntryEntry -> stringAlertEntryEntry.getKey()).collect(Collectors.toList()))); }*/ } // get alerts cache store protected IgniteCache<String, AlertEntry> getAlertsCache() { return ignite.cache(CacheNames.Alerts.name()); } }