001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2011 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.server.configuration;
021
022 import com.google.common.collect.Lists;
023 import com.thoughtworks.xstream.XStream;
024 import com.thoughtworks.xstream.converters.Converter;
025 import com.thoughtworks.xstream.converters.MarshallingContext;
026 import com.thoughtworks.xstream.converters.UnmarshallingContext;
027 import com.thoughtworks.xstream.io.HierarchicalStreamReader;
028 import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
029 import org.apache.commons.collections.CollectionUtils;
030 import org.slf4j.LoggerFactory;
031 import org.sonar.api.database.DatabaseSession;
032 import org.sonar.api.rules.Rule;
033 import org.sonar.api.rules.RuleParam;
034 import org.sonar.api.rules.RulePriority;
035 import org.sonar.jpa.dao.RulesDao;
036
037 import java.util.*;
038
039 public class RulesBackup implements Backupable {
040 private Collection<Rule> rules;
041 private RulesDao rulesDao;
042 private DatabaseSession session;
043
044 public RulesBackup(DatabaseSession session) {
045 this.rulesDao = new RulesDao(session);
046 this.session = session;
047 }
048
049 /**
050 * For tests.
051 */
052 RulesBackup(Collection<Rule> rules) {
053 this.rules = rules;
054 }
055
056 public void exportXml(SonarConfig sonarConfig) {
057 if (rules == null) {
058 rules = getUserRules();
059 }
060 sonarConfig.setRules(rules);
061 }
062
063 public void importXml(SonarConfig sonarConfig) {
064 disableUserRules();
065 if (CollectionUtils.isNotEmpty(sonarConfig.getRules())) {
066 registerUserRules(sonarConfig.getRules());
067 }
068 }
069
070 private List<Rule> getUserRules() {
071 List<Rule> rules = rulesDao.getRules();
072 List<Rule> userRules = Lists.newArrayList();
073 for (Rule rule : rules) {
074 if (rule.getParent() != null) {
075 userRules.add(rule);
076 }
077 }
078 return userRules;
079 }
080
081 private void disableUserRules() {
082 for (Rule rule : getUserRules()) {
083 rule.setEnabled(false);
084 session.save(rule);
085 }
086 }
087
088 private void registerUserRules(Collection<Rule> rules) {
089 for (Rule rule : rules) {
090 Rule parent = rule.getParent();
091 Rule matchingParentRuleInDb = rulesDao.getRuleByKey(parent.getRepositoryKey(), parent.getKey());
092 if (matchingParentRuleInDb == null) {
093 LoggerFactory.getLogger(getClass()).error("Unable to find parent rule " + parent.getRepositoryKey() + ":" + parent.getKey());
094 continue;
095 }
096
097 for (Iterator<RuleParam> irp = rule.getParams().iterator(); irp.hasNext();) {
098 RuleParam param = irp.next();
099 RuleParam matchingRPInDb = rulesDao.getRuleParam(matchingParentRuleInDb, param.getKey());
100 if (matchingRPInDb == null) {
101 LoggerFactory.getLogger(getClass()).error("Unable to find rule parameter in parent " + param.getKey());
102 irp.remove();
103 }
104 }
105
106 rule.setParent(matchingParentRuleInDb);
107 Rule matchingRuleInDb = session.getSingleResult(Rule.class,
108 "pluginName", rule.getRepositoryKey(),
109 "key", rule.getKey());
110 if (matchingRuleInDb != null) {
111 // merge
112 matchingRuleInDb.setParent(matchingParentRuleInDb);
113 matchingRuleInDb.setConfigKey(rule.getConfigKey());
114 matchingRuleInDb.setName(rule.getName());
115 matchingRuleInDb.setDescription(rule.getDescription());
116 matchingRuleInDb.setSeverity(rule.getSeverity());
117 matchingRuleInDb.setParams(rule.getParams());
118 matchingRuleInDb.setEnabled(true);
119 session.save(matchingRuleInDb);
120 } else {
121 rule.setEnabled(true);
122 session.save(rule);
123 }
124 }
125 }
126
127 public void configure(XStream xStream) {
128 xStream.alias("rule", Rule.class);
129 xStream.registerConverter(new Converter() {
130 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
131 Rule rule = (Rule) source;
132 writeNode(writer, "parentRepositoryKey", rule.getParent().getRepositoryKey());
133 writeNode(writer, "parentKey", rule.getParent().getKey());
134 writeNode(writer, "repositoryKey", rule.getRepositoryKey());
135 writeNode(writer, "key", rule.getKey());
136 writeNode(writer, "configKey", rule.getConfigKey());
137 writeNode(writer, "level", rule.getSeverity().name());
138 writeNode(writer, "name", rule.getName());
139 writeNode(writer, "description", rule.getDescription());
140
141 if (!rule.getParams().isEmpty()) {
142 writer.startNode("params");
143 for (RuleParam ruleParam : rule.getParams()) {
144 writer.startNode("param");
145 writeNode(writer, "key", ruleParam.getKey());
146 writeNode(writer, "value", ruleParam.getDefaultValue());
147 writer.endNode();
148 }
149 writer.endNode();
150 }
151 }
152
153 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
154 Rule rule = Rule.create();
155
156 Map<String, String> valuesRule = new HashMap<String, String>();
157 while (reader.hasMoreChildren()) {
158 reader.moveDown();
159 valuesRule.put(reader.getNodeName(), reader.getValue());
160 if ("params".equals(reader.getNodeName())) {
161 while (reader.hasMoreChildren()) {
162 reader.moveDown();
163 Map<String, String> valuesParam = readNode(reader);
164 rule.createParameter()
165 .setKey(valuesParam.get("key"))
166 .setDefaultValue(valuesParam.get("value"));
167 reader.moveUp();
168 }
169 }
170 reader.moveUp();
171 }
172
173 Rule parent = Rule.create()
174 .setRepositoryKey(valuesRule.get("parentRepositoryKey"))
175 .setKey(valuesRule.get("parentKey"));
176 rule.setParent(parent)
177 .setRepositoryKey(valuesRule.get("repositoryKey"))
178 .setKey(valuesRule.get("key"))
179 .setConfigKey(valuesRule.get("configKey"))
180 .setName(valuesRule.get("name"))
181 .setDescription(valuesRule.get("description"))
182 .setSeverity(RulePriority.valueOf(valuesRule.get("level")));
183 return rule;
184 }
185
186 public boolean canConvert(Class type) {
187 return Rule.class.equals(type);
188 }
189 });
190 }
191
192 private void writeNode(HierarchicalStreamWriter writer, String name, String value) {
193 writer.startNode(name);
194 writer.setValue(value);
195 writer.endNode();
196 }
197
198 private Map<String, String> readNode(HierarchicalStreamReader reader) {
199 Map<String, String> values = new HashMap<String, String>();
200 while (reader.hasMoreChildren()) {
201 reader.moveDown();
202 values.put(reader.getNodeName(), reader.getValue());
203 reader.moveUp();
204 }
205 return values;
206 }
207 }