/******************************************************************************* * Copyright (c) 2013, 2014 Lectorius, Inc. * Authors: * Vijay Pandurangan (vijayp@mitro.co) * Evan Jones (ej@mitro.co) * Adam Hilss (ahilss@mitro.co) * * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * You can contact the authors at inbound@mitro.co. *******************************************************************************/ /** * */ package co.mitro.core.alerts; import java.sql.SQLException; import java.util.Collection; import java.util.Set; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.j256.ormlite.stmt.QueryBuilder; import co.mitro.analysis.AuditLogProcessor.ActionType; import co.mitro.core.server.Manager; import co.mitro.core.server.data.DBFutureAlert; import co.mitro.core.server.data.DBIdentity; import co.mitro.core.server.data.DBProcessedAudit; /** * This is the base class for Alert Predicates. * Adding a new Predicate? You must update the map in DBFutureAlert for * things to work properly. * @author vijayp * */ public abstract class BaseAlerter { private static final Logger logger = LoggerFactory.getLogger(BaseAlerter.class); private static final long TIME_FUDGE_FACTOR_MS = 10; protected abstract DBFutureAlert.AlertPredicate getMatchingAlertType(); public abstract int createNewDBFutureAlertsForProcessedAudits(Manager mgr, Collection<DBProcessedAudit> audits, long minTimestampMs) throws SQLException; public static final class AlerterContext { public AlerterContext(Manager mgr, DBFutureAlert alert) throws SQLException { manager = mgr; dbAlertObject = alert; userToAlert = mgr.identityDao.queryForId(dbAlertObject.userIdToAlert); } public Manager manager; public DBFutureAlert dbAlertObject; public DBIdentity userToAlert; } protected enum AlertUserType {ACTOR, OBJECT} protected static QueryBuilder<DBProcessedAudit, Integer> getBuilder(AlerterContext context, Collection<ActionType> actions, AlertUserType userType) throws SQLException { QueryBuilder<DBProcessedAudit,Integer> builder = context.manager.processedAuditDao.queryBuilder(); builder.where().eq( (userType == AlertUserType.ACTOR) ? DBProcessedAudit.ACTOR_FIELD_NAME : DBProcessedAudit.AFFECTED_USER_FIELD_NAME, context.userToAlert) .and().in(DBProcessedAudit.ACTION_FIELD_NAME, Manager.makeSelectArgsFromList(actions)) .and().gt(DBProcessedAudit.TIMESTAMP_FIELD_NAME, context.dbAlertObject.enqueueTimestampMs - TIME_FUDGE_FACTOR_MS); return builder; } /** * Process the loaded alert. Return true if the predicate was met * and the action was completed. The alert object will be marked as * inactive. */ protected abstract boolean internalProcess(AlerterContext ac) throws SQLException; /** * Process an future alert. Sets the object to be inactive iff * the action has been completed. * @throws SQLException */ final public boolean processAlert(Manager mgr, DBFutureAlert futureAlert) throws SQLException { assert (getMatchingAlertType() == futureAlert.alertType); AlerterContext ac = new AlerterContext(mgr, futureAlert); long oldTime = ac.dbAlertObject.nextCheckTimestampMs; if (internalProcess(ac)) { logger.info("completed processing for db alert: {}", futureAlert.id); futureAlert.inactive = true; if (ac.dbAlertObject.nextCheckTimestampMs == oldTime) { logger.warn("Warning: email alerter did not update next check time. using default"); ac.dbAlertObject.nextCheckTimestampMs += DEFAULT_NEXT_CHECK_DELAY; } } mgr.futureAlertDao.update(futureAlert); mgr.commitTransaction(); return futureAlert.inactive; } private static final long DEFAULT_NEXT_CHECK_DELAY = TimeUnit.HOURS.toMillis(1); }