diff options
Diffstat (limited to 'sonar-deprecated')
-rw-r--r-- | sonar-deprecated/src/main/java/org/sonar/api/rules/XMLRuleParser.java | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/sonar-deprecated/src/main/java/org/sonar/api/rules/XMLRuleParser.java b/sonar-deprecated/src/main/java/org/sonar/api/rules/XMLRuleParser.java new file mode 100644 index 00000000000..17a60afeb74 --- /dev/null +++ b/sonar-deprecated/src/main/java/org/sonar/api/rules/XMLRuleParser.java @@ -0,0 +1,228 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2013 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.api.rules; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; +import com.google.common.collect.Maps; +import com.google.common.io.Closeables; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.CharEncoding; +import org.apache.commons.lang.StringUtils; +import org.codehaus.staxmate.SMInputFactory; +import org.codehaus.staxmate.in.SMHierarchicCursor; +import org.codehaus.staxmate.in.SMInputCursor; +import org.sonar.api.PropertyType; +import org.sonar.api.ServerComponent; +import org.sonar.api.utils.SonarException; +import org.sonar.check.Cardinality; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @since 2.3 + * @deprecated in 4.2. Replaced by org.sonar.api.rule.RuleDefinitions#loadXml() + */ +@Deprecated +public final class XMLRuleParser implements ServerComponent { + private static final Map<String, String> TYPE_MAP = typeMapWithDeprecatedValues(); + + public List<Rule> parse(File file) { + Reader reader = null; + try { + reader = new InputStreamReader(FileUtils.openInputStream(file), CharEncoding.UTF_8); + return parse(reader); + + } catch (IOException e) { + throw new SonarException("Fail to load the file: " + file, e); + + } finally { + Closeables.closeQuietly(reader); + } + } + + /** + * Warning : the input stream is closed in this method + */ + public List<Rule> parse(InputStream input) { + Reader reader = null; + try { + reader = new InputStreamReader(input, CharEncoding.UTF_8); + return parse(reader); + + } catch (IOException e) { + throw new SonarException("Fail to load the xml stream", e); + + } finally { + Closeables.closeQuietly(reader); + } + } + + public List<Rule> parse(Reader reader) { + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE); + xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE); + // just so it won't try to load DTD in if there's DOCTYPE + xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); + xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE); + SMInputFactory inputFactory = new SMInputFactory(xmlFactory); + try { + SMHierarchicCursor rootC = inputFactory.rootElementCursor(reader); + rootC.advance(); // <rules> + List<Rule> rules = new ArrayList<Rule>(); + + SMInputCursor rulesC = rootC.childElementCursor("rule"); + while (rulesC.getNext() != null) { + // <rule> + Rule rule = Rule.create(); + rules.add(rule); + + processRule(rule, rulesC); + } + return rules; + + } catch (XMLStreamException e) { + throw new SonarException("XML is not valid", e); + } + } + + private static void processRule(Rule rule, SMInputCursor ruleC) throws XMLStreamException { + /* BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT */ + String keyAttribute = ruleC.getAttrValue("key"); + if (StringUtils.isNotBlank(keyAttribute)) { + rule.setKey(StringUtils.trim(keyAttribute)); + } + + /* BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT */ + String priorityAttribute = ruleC.getAttrValue("priority"); + if (StringUtils.isNotBlank(priorityAttribute)) { + rule.setSeverity(RulePriority.valueOf(StringUtils.trim(priorityAttribute))); + } + + SMInputCursor cursor = ruleC.childElementCursor(); + + while (cursor.getNext() != null) { + String nodeName = cursor.getLocalName(); + + if (StringUtils.equalsIgnoreCase("name", nodeName)) { + rule.setName(StringUtils.trim(cursor.collectDescendantText(false))); + + } else if (StringUtils.equalsIgnoreCase("description", nodeName)) { + rule.setDescription(StringUtils.trim(cursor.collectDescendantText(false))); + + } else if (StringUtils.equalsIgnoreCase("key", nodeName)) { + rule.setKey(StringUtils.trim(cursor.collectDescendantText(false))); + + } else if (StringUtils.equalsIgnoreCase("configKey", nodeName)) { + rule.setConfigKey(StringUtils.trim(cursor.collectDescendantText(false))); + + } else if (StringUtils.equalsIgnoreCase("priority", nodeName)) { + rule.setSeverity(RulePriority.valueOf(StringUtils.trim(cursor.collectDescendantText(false)))); + + } else if (StringUtils.equalsIgnoreCase("cardinality", nodeName)) { + rule.setCardinality(Cardinality.valueOf(StringUtils.trim(cursor.collectDescendantText(false)))); + + } else if (StringUtils.equalsIgnoreCase("status", nodeName)) { + rule.setStatus(StringUtils.trim(cursor.collectDescendantText(false))); + + } else if (StringUtils.equalsIgnoreCase("param", nodeName)) { + processParameter(rule, cursor); + } + } + if (Strings.isNullOrEmpty(rule.getKey())) { + throw new SonarException("Node <key> is missing in <rule>"); + } + } + + private static void processParameter(Rule rule, SMInputCursor ruleC) throws XMLStreamException { + RuleParam param = rule.createParameter(); + + String keyAttribute = ruleC.getAttrValue("key"); + if (StringUtils.isNotBlank(keyAttribute)) { + /* BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT */ + param.setKey(StringUtils.trim(keyAttribute)); + } + + String typeAttribute = ruleC.getAttrValue("type"); + if (StringUtils.isNotBlank(typeAttribute)) { + /* BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT */ + param.setType(type(StringUtils.trim(typeAttribute))); + } + + SMInputCursor paramC = ruleC.childElementCursor(); + while (paramC.getNext() != null) { + String propNodeName = paramC.getLocalName(); + String propText = StringUtils.trim(paramC.collectDescendantText(false)); + if (StringUtils.equalsIgnoreCase("key", propNodeName)) { + param.setKey(propText); + + } else if (StringUtils.equalsIgnoreCase("description", propNodeName)) { + param.setDescription(propText); + + } else if (StringUtils.equalsIgnoreCase("type", propNodeName)) { + param.setType(type(propText)); + + } else if (StringUtils.equalsIgnoreCase("defaultValue", propNodeName)) { + param.setDefaultValue(propText); + } + } + if (Strings.isNullOrEmpty(param.getKey())) { + throw new SonarException("Node <key> is missing in <param>"); + } + } + + private static Map<String, String> typeMapWithDeprecatedValues() { + Map<String, String> map = Maps.newHashMap(); + map.put("i", PropertyType.INTEGER.name()); + map.put("s", PropertyType.STRING.name()); + map.put("b", PropertyType.BOOLEAN.name()); + map.put("r", PropertyType.REGULAR_EXPRESSION.name()); + map.put("s{}", "s{}"); + map.put("i{}", "i{}"); + for (PropertyType propertyType : PropertyType.values()) { + map.put(propertyType.name(), propertyType.name()); + } + return map; + } + + @VisibleForTesting + static String type(String type) { + String validType = TYPE_MAP.get(type); + if (null != validType) { + return validType; + } + + if (type.matches(".\\[.+\\]")) { + return type; + } + throw new SonarException("Invalid property type [" + type + "]"); + } + +} |