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.thoughtworks.xstream.XStream; 023 import com.thoughtworks.xstream.converters.Converter; 024 import com.thoughtworks.xstream.converters.MarshallingContext; 025 import com.thoughtworks.xstream.converters.UnmarshallingContext; 026 import com.thoughtworks.xstream.io.HierarchicalStreamReader; 027 import com.thoughtworks.xstream.io.HierarchicalStreamWriter; 028 import org.apache.commons.collections.CollectionUtils; 029 import org.slf4j.LoggerFactory; 030 import org.sonar.api.database.DatabaseSession; 031 import org.sonar.api.measures.Metric; 032 import org.sonar.api.profiles.Alert; 033 import org.sonar.api.profiles.RulesProfile; 034 import org.sonar.api.rules.*; 035 import org.sonar.jpa.dao.RulesDao; 036 037 import java.util.*; 038 039 public class ProfilesBackup implements Backupable { 040 041 private Collection<RulesProfile> profiles; 042 private DatabaseSession session; 043 044 public ProfilesBackup(DatabaseSession session) { 045 this.session = session; 046 } 047 048 /** 049 * for unit tests 050 */ 051 ProfilesBackup(Collection<RulesProfile> profiles) { 052 this.profiles = profiles; 053 } 054 055 public void configure(XStream xStream) { 056 xStream.alias("profile", RulesProfile.class); 057 xStream.alias("alert", Alert.class); 058 xStream.alias("active-rule", ActiveRule.class); 059 xStream.aliasField("active-rules", RulesProfile.class, "activeRules"); 060 xStream.aliasField("default-profile", RulesProfile.class, "defaultProfile"); 061 xStream.omitField(RulesProfile.class, "id"); 062 xStream.omitField(RulesProfile.class, "projects"); 063 xStream.registerConverter(getActiveRuleConverter()); 064 xStream.registerConverter(getAlertsConverter()); 065 } 066 067 public void exportXml(SonarConfig sonarConfig) { 068 this.profiles = (this.profiles == null ? session.getResults(RulesProfile.class) : this.profiles); 069 // the profiles objects must be cloned to avoid issues CGLib 070 List<RulesProfile> cloned = new ArrayList<RulesProfile>(); 071 for (RulesProfile profile : this.profiles) { 072 cloned.add((RulesProfile) profile.clone()); 073 } 074 075 sonarConfig.setProfiles(cloned); 076 } 077 078 public void importXml(SonarConfig sonarConfig) { 079 if (CollectionUtils.isNotEmpty(sonarConfig.getProfiles())) { 080 ProfilesManager profilesManager = new ProfilesManager(session, null); 081 profilesManager.deleteAllProfiles(); 082 083 RulesDao rulesDao = new RulesDao(session); 084 for (RulesProfile profile : sonarConfig.getProfiles()) { 085 importProfile(rulesDao, profile); 086 } 087 } 088 } 089 090 public void importProfile(RulesDao rulesDao, RulesProfile toImport) { 091 if (toImport.getEnabled() == null) { 092 // backward-compatibility with versions < 2.6. The field "enabled" did not exist. Default value is true. 093 toImport.setEnabled(true); 094 } 095 if (toImport.getVersion() == 0) { 096 // backward-compatibility with versions < 2.9. The field "version" did not exist. Default value is 1. 097 toImport.setVersion(1); 098 } 099 if (toImport.getUsed() == null) { 100 // backward-compatibility with versions < 2.9. The field "used_profile" did not exist. Default value is false. 101 toImport.setUsed(false); 102 } 103 importActiveRules(rulesDao, toImport); 104 importAlerts(toImport); 105 session.save(toImport); 106 } 107 108 private void importAlerts(RulesProfile profile) { 109 if (profile.getAlerts() != null) { 110 for (Iterator<Alert> ia = profile.getAlerts().iterator(); ia.hasNext();) { 111 Alert alert = ia.next(); 112 Metric unMarshalledMetric = alert.getMetric(); 113 String validKey = unMarshalledMetric.getKey(); 114 Metric matchingMetricInDb = session.getSingleResult(Metric.class, "key", validKey); 115 if (matchingMetricInDb == null) { 116 LoggerFactory.getLogger(getClass()).error("Unable to find metric " + validKey); 117 ia.remove(); 118 continue; 119 } 120 alert.setMetric(matchingMetricInDb); 121 alert.setRulesProfile(profile); 122 } 123 } 124 } 125 126 private void importActiveRules(RulesDao rulesDao, RulesProfile profile) { 127 for (Iterator<ActiveRule> iar = profile.getActiveRules(true).iterator(); iar.hasNext();) { 128 ActiveRule activeRule = iar.next(); 129 Rule unMarshalledRule = activeRule.getRule(); 130 Rule matchingRuleInDb = rulesDao.getRuleByKey(unMarshalledRule.getRepositoryKey(), unMarshalledRule.getKey()); 131 if (matchingRuleInDb == null) { 132 LoggerFactory.getLogger(getClass()).error( 133 "Unable to find active rule " + unMarshalledRule.getRepositoryKey() + ":" + unMarshalledRule.getKey()); 134 iar.remove(); 135 continue; 136 } 137 activeRule.setRule(matchingRuleInDb); 138 activeRule.setRulesProfile(profile); 139 activeRule.getActiveRuleParams(); 140 for (Iterator<ActiveRuleParam> irp = activeRule.getActiveRuleParams().iterator(); irp.hasNext();) { 141 ActiveRuleParam activeRuleParam = irp.next(); 142 RuleParam unMarshalledRP = activeRuleParam.getRuleParam(); 143 RuleParam matchingRPInDb = rulesDao.getRuleParam(matchingRuleInDb, unMarshalledRP.getKey()); 144 if (matchingRPInDb == null) { 145 LoggerFactory.getLogger(getClass()).error("Unable to find active rule parameter " + unMarshalledRP.getKey()); 146 irp.remove(); 147 continue; 148 } 149 activeRuleParam.setActiveRule(activeRule); 150 activeRuleParam.setRuleParam(matchingRPInDb); 151 } 152 } 153 } 154 155 private Converter getAlertsConverter() { 156 return new Converter() { 157 158 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { 159 Alert alert = (Alert) source; 160 writeNode(writer, "operator", alert.getOperator()); 161 writeNode(writer, "value-error", alert.getValueError()); 162 writeNode(writer, "value-warning", alert.getValueWarning()); 163 writeNode(writer, "metric-key", alert.getMetric().getKey()); 164 } 165 166 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 167 Map<String, String> values = readNode(reader); 168 return new Alert(null, new Metric(values.get("metric-key")), values.get("operator"), values.get("value-error"), 169 values.get("value-warning")); 170 } 171 172 public boolean canConvert(Class type) { 173 return type.equals(Alert.class); 174 } 175 }; 176 } 177 178 private Converter getActiveRuleConverter() { 179 return new Converter() { 180 181 public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { 182 ActiveRule rule = (ActiveRule) source; 183 writeNode(writer, "key", rule.getRule().getKey()); 184 writeNode(writer, "plugin", rule.getRule().getRepositoryKey()); 185 writeNode(writer, "level", rule.getSeverity().name()); 186 writeNode(writer, "inheritance", rule.getInheritance()); 187 188 if (!rule.getActiveRuleParams().isEmpty()) { 189 writer.startNode("params"); 190 for (ActiveRuleParam activeRuleParam : rule.getActiveRuleParams()) { 191 writer.startNode("param"); 192 writeNode(writer, "key", activeRuleParam.getRuleParam().getKey()); 193 writeNode(writer, "value", activeRuleParam.getValue()); 194 writer.endNode(); 195 } 196 writer.endNode(); 197 } 198 } 199 200 public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { 201 Map<String, String> valuesRule = new HashMap<String, String>(); 202 List<ActiveRuleParam> params = new ArrayList<ActiveRuleParam>(); 203 while (reader.hasMoreChildren()) { 204 reader.moveDown(); 205 valuesRule.put(reader.getNodeName(), reader.getValue()); 206 if ("params".equals(reader.getNodeName())) { 207 while (reader.hasMoreChildren()) { 208 reader.moveDown(); 209 Map<String, String> valuesParam = readNode(reader); 210 ActiveRuleParam activeRuleParam = new ActiveRuleParam(null, new RuleParam(null, valuesParam.get("key"), null, null), 211 valuesParam.get("value")); 212 params.add(activeRuleParam); 213 reader.moveUp(); 214 } 215 } 216 reader.moveUp(); 217 } 218 219 ActiveRule activeRule = new ActiveRule(null, new Rule(valuesRule.get("plugin"), valuesRule.get("key")), RulePriority 220 .valueOf(valuesRule.get("level"))); 221 activeRule.setActiveRuleParams(params); 222 if (valuesRule.containsKey("inheritance")) { 223 activeRule.setInheritance(valuesRule.get("inheritance")); 224 } 225 return activeRule; 226 } 227 228 public boolean canConvert(Class type) { 229 return type.equals(ActiveRule.class); 230 } 231 }; 232 } 233 234 private void writeNode(HierarchicalStreamWriter writer, String name, String value) { 235 if (value != null) { 236 writer.startNode(name); 237 writer.setValue(value); 238 writer.endNode(); 239 } 240 } 241 242 private Map<String, String> readNode(HierarchicalStreamReader reader) { 243 Map<String, String> values = new HashMap<String, String>(); 244 while (reader.hasMoreChildren()) { 245 reader.moveDown(); 246 values.put(reader.getNodeName(), reader.getValue()); 247 reader.moveUp(); 248 } 249 return values; 250 } 251 252 }