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