/**
* 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.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.logging.Level;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rapidminer.RapidMiner;
import com.rapidminer.RapidMiner.ExecutionMode;
import com.rapidminer.studio.internal.RuleProvider;
import com.rapidminer.studio.internal.RuleProviderRegistry;
import com.rapidminer.tools.I18N;
import com.rapidminer.tools.LogService;
/**
* This class loads the CTA rules either from a local test file or from Nexus.
*
* @author Jonas Wilms-Pfau, Marco Boeck
* @since 7.5
*
*/
enum RuleService {
INSTANCE;
private final Set<String> PROHIBITED_KEYWORDS = new HashSet<>();
private Set<VerifiableRule> rules = new HashSet<>();
private RuleService() {
PROHIBITED_KEYWORDS.add("JOIN");
PROHIBITED_KEYWORDS.add("CREATE");
PROHIBITED_KEYWORDS.add("INSERT");
PROHIBITED_KEYWORDS.add("UPDATE");
PROHIBITED_KEYWORDS.add("DELETE");
PROHIBITED_KEYWORDS.add("DROP");
PROHIBITED_KEYWORDS.add("ALTER");
PROHIBITED_KEYWORDS.add("MERGE");
PROHIBITED_KEYWORDS.add("TRUNCATE");
PROHIBITED_KEYWORDS.add("SET");
PROHIBITED_KEYWORDS.add("SHUTDOWN");
PROHIBITED_KEYWORDS.add("COMMIT");
PROHIBITED_KEYWORDS.add("GRANT");
PROHIBITED_KEYWORDS.add("CHECKPOINT");
PROHIBITED_KEYWORDS.add("SAVEPOINT");
PROHIBITED_KEYWORDS.add("PREPARE");
PROHIBITED_KEYWORDS.add("REVOKE");
PROHIBITED_KEYWORDS.add("ROLLBACK");
PROHIBITED_KEYWORDS.add("CONSTRAINT");
PROHIBITED_KEYWORDS.add("RUNSCRIPT");
PROHIBITED_KEYWORDS.add("BACKUP");
PROHIBITED_KEYWORDS.add("CALL");
PROHIBITED_KEYWORDS.add("SCRIPT");
PROHIBITED_KEYWORDS.add("ANALYZE");
PROHIBITED_KEYWORDS.add("COMMENT");
PROHIBITED_KEYWORDS.add("EXPLAIN");
PROHIBITED_KEYWORDS.add("SHOW");
reloadRules();
}
public Set<VerifiableRule> getRules() {
return rules;
}
/**
* Reloads the CTA rules from either local file or Nexus.
*/
public void reloadRules() {
if (!RapidMiner.getExecutionMode().equals(ExecutionMode.UI)) {
return;
}
ObjectMapper mapper = new ObjectMapper();
List<VerifiableRule> newRules = null;
Iterator<RuleProvider> ruleProvider = RuleProviderRegistry.INSTANCE.getRuleProvider().iterator();
while (ruleProvider.hasNext() && newRules == null) {
RuleProvider provider = ruleProvider.next();
try (InputStream ruleJson = provider.getRuleJson()) {
if (ruleJson != null) {
newRules = checkAndConvertRules(mapper.readValue(ruleJson, new TypeReference<List<Rule>>() {
}));
} else {
LogService.getRoot().log(Level.FINE, I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.tools.usagestats.RuleService.load.empty", provider.getClass().getSimpleName()));
}
} catch (Exception e) {
LogService.getRoot().log(Level.WARNING, I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.tools.usagestats.RuleService.load.failure", provider.getClass().getSimpleName()), e);
break;
}
}
if (newRules != null) {
rules.retainAll(newRules);
rules.addAll(newRules);
}
}
/**
* Converts JSON rules list to a {@link VerifiableRule} list. Also checks that rules do not
* violate the {@link #PROHIBITED_KEYWORDS} SQL blacklist. If any rules does, it is skipped.
*
* @param jsonRules
* the input rule list
* @return the output verifiable rule list
*/
private List<VerifiableRule> checkAndConvertRules(List<Rule> jsonRules) {
List<VerifiableRule> newRules = new ArrayList<>(jsonRules.size());
ruleLoop: for (Rule rule : jsonRules) {
for (String sql : rule.getQueries()) {
for (String prohibited : PROHIBITED_KEYWORDS) {
if (sql.toUpperCase(Locale.ENGLISH).contains(prohibited)) {
// prohibited keyword found, skip this rule
LogService.getRoot().log(Level.WARNING,
"com.rapidminer.tools.usagestats.RuleService.load_invalid_sql",
new Object[] { rule.getId(), prohibited });
continue ruleLoop;
}
}
}
newRules.add(new VerifiableRule(rule));
}
return newRules;
}
}