/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program 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, 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 * 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.rapidminer.tools.usagestats; import java.sql.SQLException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import com.rapidminer.tools.I18N; import com.rapidminer.tools.LogService; /** * Verifiable Rule which is a mechanism to check if the passed {@link Rule} is fulfilled. If so, the * message of the rule is displayed and its user interaction is stored in the CTA database. * * @author Jonas Wilms-Pfau, Marco Boeck * @since 7.5.0 * */ class VerifiableRule { /** Conversion factor to convert a second into a millisecond */ private static final long SECOND_TO_MILLISECOND = 1000; /** Timestamp of the last execution */ private long lastRun = 0l; /** Only run once at a time */ private final AtomicBoolean isRunning = new AtomicBoolean(false); /** flag to indicate if CTA is currently displayed to user */ private final AtomicBoolean isDisplaying = new AtomicBoolean(false); /** the rule parsed from JSON */ private final Rule rule; /** * Creates a verifiable rule based on the given {@link Rule}. * * @param rule */ VerifiableRule(Rule rule) { this.rule = rule; } /** * Check if the rule should be verified, if yes execute the queries against the CTA Database, if * they are all fulfilled display the message * * @return {@code true} if the rule is not running/displaying and all rule queries return true; * {@code false} otherwise */ public boolean isRuleFulfilled() { // Check if the rule should be executed if (isDisplaying.get() == false && isRunning.get() == false && System.currentTimeMillis() >= lastRun + rule.getInterval() * SECOND_TO_MILLISECOND) { // Try to get the lock if (isRunning.compareAndSet(false, true)) { try { lastRun = System.currentTimeMillis(); return CtaDao.INSTANCE.verify(rule); } catch (SQLException e) { // Don't run this rule again today lastRun += TimeUnit.DAYS.toMillis(1); LogService.getRoot().log(Level.WARNING, I18N.getMessage(LogService.getRoot().getResourceBundle(), "com.rapidminer.tools.usagestats.VerifiableRule.verification.failed", rule.getId()), e); } finally { isRunning.set(false); } } } return false; } /** * Returns the {@link Rule} for this rule. * * @return the rule, never {@code null} */ public Rule getRule() { return rule; } /** * Set the flag that this rule is displaying. Rules which are displaying cannot return * {@code true} for {@link #isRuleFulfilled()}. */ public void setDisplaying(boolean displaying) { isDisplaying.set(displaying); } /** * Returns whether this rule is currently displaying its CTA. * * @return {@code true} if the rule is currently displaying; {@code false} otherwise */ public boolean isDisplaying() { return isDisplaying.get(); } @Override public String toString() { return rule.toString() + " Last run: " + lastRun; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (rule == null ? 0 : rule.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } VerifiableRule other = (VerifiableRule) obj; if (rule == null) { if (other.rule != null) { return false; } } else if (!rule.equals(other.rule)) { return false; } return true; } }