/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.model; import org.candlepin.cache.CandlepinCacheRegions; import org.candlepin.common.exceptions.NotFoundException; import org.candlepin.common.util.VersionUtil; import org.candlepin.util.Util; import com.google.inject.persist.Transactional; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; import java.util.Date; /** * RulesCurator */ public class RulesCurator extends AbstractHibernateCurator<Rules> { private static Logger log = LoggerFactory.getLogger(RulesCurator.class); public static final String DEFAULT_RULES_FILE = "/rules/rules.js"; /* * Current rules API major version number. (the x in x.y) If a rules file does not * match this major version number exactly, we do not import the rules. */ public static final int RULES_API_VERSION = 5; public RulesCurator() { super(Rules.class); } /** * updates the rules to the given values. * * @param updatedRules latest rules * @return a copy of the latest rules */ @Transactional public Rules update(Rules updatedRules) { updatedRules.setRulesSource(Rules.RulesSourceEnum.DATABASE); Rules result = this.create(updatedRules); return result; } @Override @Transactional public Rules create(Rules toCreate) { Rules current = getDbRules(); if (current != null && !VersionUtil.getRulesVersionCompatibility( current.getVersion(), toCreate.getVersion())) { log.debug("Inbound rules not compatible with current rules; rejecting creation"); return current; } log.debug("Creating new rules: {}", toCreate); return super.create(toCreate); } public Rules getDbRules() { return (Rules) this.currentSession().createCriteria(Rules.class) .addOrder(Order.desc("updated")) .setMaxResults(1) .uniqueResult(); } public void updateDbRules() { Rules dbRules = getDbRules(); // Load rules from RPM, we need to know it's version before we know which // rules to use: Rules rpmRules = rulesFromFile(getDefaultRulesFile()); log.debug("RPM Rules version: {}", rpmRules.getVersion()); if (dbRules == null || !VersionUtil.getRulesVersionCompatibility(rpmRules.getVersion(), dbRules.getVersion())) { this.resetToRpmRules(); } } /** * @return the rules */ public Rules getRules() { Rules dbRules = getDbRules(); if (dbRules == null) { log.error("There is no rules file in the database, something is very wrong."); throw new NotFoundException(i18n.tr("No rules file found in the database")); } return dbRules; } public Date getUpdatedFromDB() { return (Date) this.currentSession().createCriteria(Rules.class) .setCacheable(true) .setCacheRegion(CandlepinCacheRegions.FIVE_SECONDS_QUERY_CACHE) .setProjection(Projections.max("updated")) .uniqueResult(); } /** * Get the last updated timestamp for the rules (either from disk or db), * without reading in the full rules file. * * @return the last updated timestamp for the rules */ public Date getUpdated() { Date updated = getUpdatedFromDB(); if (updated != null) { return updated; } URL rulesUrl = this.getClass().getResource(getDefaultRulesFile()); File rulesFile; try { rulesFile = new File(rulesUrl.toURI()); } catch (URISyntaxException e) { throw new CuratorException(e); } return new Date(rulesFile.lastModified()); } @Transactional public void resetToRpmRules() { currentSession().createQuery("DELETE FROM Rules").executeUpdate(); this.create(rulesFromFile(DEFAULT_RULES_FILE)); } @Override @Transactional public void delete(Rules toDelete) { this.resetToRpmRules(); } private Rules rulesFromFile(String path) { InputStream is = this.getClass().getResourceAsStream(path); Rules result = new Rules(Util.readFile(is)); result.setRulesSource(Rules.RulesSourceEnum.DEFAULT); return result; } protected String getDefaultRulesFile() { return DEFAULT_RULES_FILE; } }