001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 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> userRules = Lists.newArrayList();
072 for (Rule rule : rulesDao.getRules()) {
073 if (rule.getParent() != null) {
074 userRules.add(rule);
075 }
076 }
077 return userRules;
078 }
079
080 private void disableUserRules() {
081 LoggerFactory.getLogger(getClass()).info("Disable rules created by user");
082 for (Rule rule : getUserRules()) {
083 rule.setEnabled(false);
084 session.save(rule);
085 }
086 }
087
088 private void registerUserRules(Collection<Rule> rules) {
089 LoggerFactory.getLogger(getClass()).info("Restore rules");
090 for (Rule rule : rules) {
091 Rule parent = rule.getParent();
092 Rule matchingParentRuleInDb = rulesDao.getRuleByKey(parent.getRepositoryKey(), parent.getKey());
093 if (matchingParentRuleInDb == null) {
094 LoggerFactory.getLogger(getClass()).error("Unable to find parent rule " + parent.getRepositoryKey() + ":" + parent.getKey());
095 continue;
096 }
097
098 for (Iterator<RuleParam> irp = rule.getParams().iterator(); irp.hasNext();) {
099 RuleParam param = irp.next();
100 RuleParam matchingRPInDb = rulesDao.getRuleParam(matchingParentRuleInDb, param.getKey());
101 if (matchingRPInDb == null) {
102 LoggerFactory.getLogger(getClass()).error("Unable to find rule parameter in parent " + param.getKey());
103 irp.remove();
104 }
105 }
106
107 rule.setParent(matchingParentRuleInDb);
108 Rule matchingRuleInDb = session.getSingleResult(Rule.class,
109 "pluginName", rule.getRepositoryKey(),
110 "key", rule.getKey());
111 if (matchingRuleInDb != null) {
112 // merge
113 matchingRuleInDb.setParent(matchingParentRuleInDb);
114 matchingRuleInDb.setConfigKey(rule.getConfigKey());
115 matchingRuleInDb.setName(rule.getName());
116 matchingRuleInDb.setDescription(rule.getDescription());
117 matchingRuleInDb.setSeverity(rule.getSeverity());
118 matchingRuleInDb.setParams(rule.getParams());
119 matchingRuleInDb.setEnabled(true);
120 session.save(matchingRuleInDb);
121 } else {
122 rule.setEnabled(true);
123 session.save(rule);
124 }
125 }
126 }
127
128 public void configure(XStream xStream) {
129 xStream.alias("rule", Rule.class);
130 xStream.registerConverter(new Converter() {
131 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
132 Rule rule = (Rule) source;
133 writeNode(writer, "parentRepositoryKey", rule.getParent().getRepositoryKey());
134 writeNode(writer, "parentKey", rule.getParent().getKey());
135 writeNode(writer, "repositoryKey", rule.getRepositoryKey());
136 writeNode(writer, "key", rule.getKey());
137 writeNode(writer, "configKey", rule.getConfigKey());
138 writeNode(writer, "level", rule.getSeverity().name());
139 writeNode(writer, "name", rule.getName());
140 writeNode(writer, "description", rule.getDescription());
141
142 if (!rule.getParams().isEmpty()) {
143 writer.startNode("params");
144 for (RuleParam ruleParam : rule.getParams()) {
145 writer.startNode("param");
146 writeNode(writer, "key", ruleParam.getKey());
147 writeNode(writer, "value", ruleParam.getDefaultValue());
148 writer.endNode();
149 }
150 writer.endNode();
151 }
152 }
153
154 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
155 Rule rule = Rule.create();
156
157 Map<String, String> valuesRule = new HashMap<String, String>();
158 while (reader.hasMoreChildren()) {
159 reader.moveDown();
160 valuesRule.put(reader.getNodeName(), reader.getValue());
161 if ("params".equals(reader.getNodeName())) {
162 while (reader.hasMoreChildren()) {
163 reader.moveDown();
164 Map<String, String> valuesParam = readNode(reader);
165 rule.createParameter()
166 .setKey(valuesParam.get("key"))
167 .setDefaultValue(valuesParam.get("value"));
168 reader.moveUp();
169 }
170 }
171 reader.moveUp();
172 }
173
174 Rule parent = Rule.create()
175 .setRepositoryKey(valuesRule.get("parentRepositoryKey"))
176 .setKey(valuesRule.get("parentKey"));
177 rule.setParent(parent)
178 .setRepositoryKey(valuesRule.get("repositoryKey"))
179 .setKey(valuesRule.get("key"))
180 .setConfigKey(valuesRule.get("configKey"))
181 .setName(valuesRule.get("name"))
182 .setDescription(valuesRule.get("description"))
183 .setSeverity(RulePriority.valueOf(valuesRule.get("level")));
184 return rule;
185 }
186
187 public boolean canConvert(Class type) {
188 return Rule.class.equals(type);
189 }
190 });
191 }
192
193 private void writeNode(HierarchicalStreamWriter writer, String name, String value) {
194 writer.startNode(name);
195 writer.setValue(value);
196 writer.endNode();
197 }
198
199 private Map<String, String> readNode(HierarchicalStreamReader reader) {
200 Map<String, String> values = new HashMap<String, String>();
201 while (reader.hasMoreChildren()) {
202 reader.moveDown();
203 values.put(reader.getNodeName(), reader.getValue());
204 reader.moveUp();
205 }
206 return values;
207 }
208 }