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 org.apache.commons.lang.ObjectUtils; 023 import org.codehaus.plexus.util.StringUtils; 024 import org.sonar.api.database.DatabaseSession; 025 import org.sonar.api.database.model.ResourceModel; 026 import org.sonar.api.profiles.RulesProfile; 027 import org.sonar.api.rules.*; 028 import org.sonar.api.utils.ValidationMessages; 029 import org.sonar.jpa.dao.BaseDao; 030 import org.sonar.jpa.dao.RulesDao; 031 032 import java.util.List; 033 034 public class ProfilesManager extends BaseDao { 035 036 private RulesDao rulesDao; 037 038 public ProfilesManager(DatabaseSession session, RulesDao rulesDao) { 039 super(session); 040 this.rulesDao = rulesDao; 041 } 042 043 public void renameProfile(int profileId, String newProfileName) { 044 RulesProfile profile = getSession().getSingleResult(RulesProfile.class, "id", profileId); 045 if (profile != null && !profile.getProvided()) { 046 String hql = "UPDATE " + RulesProfile.class.getSimpleName() + " o SET o.parentName=:newName WHERE o.parentName=:oldName"; 047 getSession().getEntityManager().createQuery(hql) 048 .setParameter("oldName", profile.getName()) 049 .setParameter("newName", newProfileName) 050 .executeUpdate(); 051 profile.setName(newProfileName); 052 getSession().save(profile); 053 getSession().commit(); 054 } 055 } 056 057 public void copyProfile(int profileId, String newProfileName) { 058 RulesProfile profile = getSession().getSingleResult(RulesProfile.class, "id", profileId); 059 RulesProfile toImport = (RulesProfile) profile.clone(); 060 toImport.setName(newProfileName); 061 toImport.setDefaultProfile(false); 062 toImport.setProvided(false); 063 ProfilesBackup pb = new ProfilesBackup(getSession()); 064 pb.importProfile(rulesDao, toImport); 065 getSession().commit(); 066 } 067 068 public void deleteProfile(int profileId) { 069 RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId); 070 if (profile != null && !profile.getProvided() && getChildren(profile).isEmpty()) { 071 // Remove history of rule changes 072 String hqlDeleteRc = "DELETE " + ActiveRuleChange.class.getSimpleName() + " rc WHERE rc.rulesProfile=:rulesProfile"; 073 getSession().createQuery(hqlDeleteRc).setParameter("rulesProfile", profile).executeUpdate(); 074 075 String hql = "UPDATE " + ResourceModel.class.getSimpleName() + " o SET o.rulesProfile=null WHERE o.rulesProfile=:rulesProfile"; 076 getSession().createQuery(hql).setParameter("rulesProfile", profile).executeUpdate(); 077 getSession().remove(profile); 078 getSession().commit(); 079 } 080 } 081 082 public void deleteAllProfiles() { 083 // Remove history of rule changes 084 String hqlDeleteRc = "DELETE " + ActiveRuleChange.class.getSimpleName() + " rc"; 085 getSession().createQuery(hqlDeleteRc).executeUpdate(); 086 087 String hql = "UPDATE " + ResourceModel.class.getSimpleName() + " o SET o.rulesProfile = null WHERE o.rulesProfile IS NOT NULL"; 088 getSession().createQuery(hql).executeUpdate(); 089 List profiles = getSession().createQuery("FROM " + RulesProfile.class.getSimpleName()).getResultList(); 090 for (Object profile : profiles) { 091 getSession().removeWithoutFlush(profile); 092 } 093 getSession().commit(); 094 } 095 096 // Managing inheritance of profiles 097 098 public ValidationMessages changeParentProfile(Integer profileId, String parentName, String userName) { 099 ValidationMessages messages = ValidationMessages.create(); 100 RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId); 101 if (profile != null && !profile.getProvided()) { 102 RulesProfile oldParent = getParentProfile(profile); 103 RulesProfile newParent = getProfile(profile.getLanguage(), parentName); 104 if (isCycle(profile, newParent)) { 105 messages.addWarningText("Please do not select a child profile as parent."); 106 return messages; 107 } 108 // Deactivate all inherited rules 109 if (oldParent != null) { 110 for (ActiveRule activeRule : oldParent.getActiveRules()) { 111 deactivate(profile, activeRule.getRule(), userName); 112 } 113 } 114 // Activate all inherited rules 115 if (newParent != null) { 116 for (ActiveRule activeRule : newParent.getActiveRules()) { 117 activateOrChange(profile, activeRule, userName); 118 } 119 } 120 profile.setParentName(newParent == null ? null : newParent.getName()); 121 getSession().saveWithoutFlush(profile); 122 getSession().commit(); 123 } 124 return messages; 125 } 126 127 /** 128 * Rule was activated 129 */ 130 public void activated(int profileId, int activeRuleId, String userName) { 131 ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId); 132 RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId); 133 ruleEnabled(profile, activeRule, userName); 134 // Notify child profiles 135 activatedOrChanged(profileId, activeRuleId, userName); 136 } 137 138 /** 139 * Rule param was changed 140 */ 141 public void ruleParamChanged(int profileId, int activeRuleId, String paramKey, String oldValue, String newValue, String userName) { 142 ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId); 143 RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId); 144 145 ruleParamChanged(profile, activeRule.getRule(), paramKey, oldValue, newValue, userName); 146 147 // Notify child profiles 148 activatedOrChanged(profileId, activeRuleId, userName); 149 } 150 151 /** 152 * Rule severity was changed 153 */ 154 public void ruleSeverityChanged(int profileId, int activeRuleId, RulePriority oldSeverity, RulePriority newSeverity, String userName) { 155 ActiveRule activeRule = getSession().getEntity(ActiveRule.class, activeRuleId); 156 RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId); 157 158 ruleSeverityChanged(profile, activeRule.getRule(), oldSeverity, newSeverity, userName); 159 160 // Notify child profiles 161 activatedOrChanged(profileId, activeRuleId, userName); 162 } 163 164 /** 165 * Rule was activated/changed in parent profile. 166 */ 167 private void activatedOrChanged(int parentProfileId, int activeRuleId, String userName) { 168 ActiveRule parentActiveRule = getSession().getEntity(ActiveRule.class, activeRuleId); 169 if (parentActiveRule.isInherited()) { 170 parentActiveRule.setInheritance(ActiveRule.OVERRIDES); 171 getSession().saveWithoutFlush(parentActiveRule); 172 } 173 for (RulesProfile child : getChildren(parentProfileId)) { 174 activateOrChange(child, parentActiveRule, userName); 175 } 176 getSession().commit(); 177 } 178 179 /** 180 * Rule was deactivated in parent profile. 181 */ 182 public void deactivated(int parentProfileId, int deactivatedRuleId, String userName) { 183 ActiveRule parentActiveRule = getSession().getEntity(ActiveRule.class, deactivatedRuleId); 184 RulesProfile profile = getSession().getEntity(RulesProfile.class, parentProfileId); 185 ruleDisabled(profile, parentActiveRule, userName); 186 for (RulesProfile child : getChildren(parentProfileId)) { 187 deactivate(child, parentActiveRule.getRule(), userName); 188 } 189 getSession().commit(); 190 } 191 192 /** 193 * @return true, if setting <code>childProfile</code> as a child of <code>parentProfile</code> adds cycle 194 */ 195 boolean isCycle(RulesProfile childProfile, RulesProfile parentProfile) { 196 while (parentProfile != null) { 197 if (childProfile.equals(parentProfile)) { 198 return true; 199 } 200 parentProfile = getParentProfile(parentProfile); 201 } 202 return false; 203 } 204 205 public void revert(int profileId, int activeRuleId, String userName) { 206 RulesProfile profile = getSession().getEntity(RulesProfile.class, profileId); 207 ActiveRule oldActiveRule = getSession().getEntity(ActiveRule.class, activeRuleId); 208 if (oldActiveRule != null && oldActiveRule.doesOverride()) { 209 ActiveRule parentActiveRule = getParentProfile(profile).getActiveRule(oldActiveRule.getRule()); 210 removeActiveRule(profile, oldActiveRule); 211 ActiveRule newActiveRule = (ActiveRule) parentActiveRule.clone(); 212 newActiveRule.setRulesProfile(profile); 213 newActiveRule.setInheritance(ActiveRule.INHERITED); 214 profile.addActiveRule(newActiveRule); 215 getSession().saveWithoutFlush(newActiveRule); 216 217 // Compute change 218 ruleChanged(profile, oldActiveRule, newActiveRule, userName); 219 220 for (RulesProfile child : getChildren(profile)) { 221 activateOrChange(child, newActiveRule, userName); 222 } 223 224 getSession().commit(); 225 } 226 } 227 228 private synchronized void incrementProfileVersionIfNeeded(RulesProfile profile) { 229 if (profile.getUsed()) { 230 profile.setVersion(profile.getVersion() + 1); 231 profile.setUsed(false); 232 getSession().saveWithoutFlush(profile); 233 } 234 } 235 236 /** 237 * Deal with creation of ActiveRuleChange item when a rule param is changed on a profile 238 */ 239 private void ruleParamChanged(RulesProfile profile, Rule rule, String paramKey, String oldValue, String newValue, String userName) { 240 incrementProfileVersionIfNeeded(profile); 241 ActiveRuleChange rc = new ActiveRuleChange(userName, profile, rule); 242 if (!StringUtils.equals(oldValue, newValue)) { 243 rc.setParameterChange(paramKey, oldValue, newValue); 244 getSession().saveWithoutFlush(rc); 245 } 246 } 247 248 /** 249 * Deal with creation of ActiveRuleChange item when a rule severity is changed on a profile 250 */ 251 private void ruleSeverityChanged(RulesProfile profile, Rule rule, RulePriority oldSeverity, RulePriority newSeverity, String userName) { 252 incrementProfileVersionIfNeeded(profile); 253 ActiveRuleChange rc = new ActiveRuleChange(userName, profile, rule); 254 if (!ObjectUtils.equals(oldSeverity, newSeverity)) { 255 rc.setOldSeverity(oldSeverity); 256 rc.setNewSeverity(newSeverity); 257 getSession().saveWithoutFlush(rc); 258 } 259 } 260 261 /** 262 * Deal with creation of ActiveRuleChange item when a rule is changed (severity and/or param(s)) on a profile 263 */ 264 private void ruleChanged(RulesProfile profile, ActiveRule oldActiveRule, ActiveRule newActiveRule, String userName) { 265 incrementProfileVersionIfNeeded(profile); 266 ActiveRuleChange rc = new ActiveRuleChange(userName, profile, newActiveRule.getRule()); 267 268 if (oldActiveRule.getSeverity() != newActiveRule.getSeverity()) { 269 rc.setOldSeverity(oldActiveRule.getSeverity()); 270 rc.setNewSeverity(newActiveRule.getSeverity()); 271 } 272 if (oldActiveRule.getRule().getParams() != null) { 273 for (RuleParam p : oldActiveRule.getRule().getParams()) { 274 String oldParam = oldActiveRule.getParameter(p.getKey()); 275 String newParam = newActiveRule.getParameter(p.getKey()); 276 if (!StringUtils.equals(oldParam, newParam)) { 277 rc.setParameterChange(p.getKey(), oldParam, newParam); 278 } 279 } 280 } 281 282 getSession().saveWithoutFlush(rc); 283 } 284 285 /** 286 * Deal with creation of ActiveRuleChange item when a rule is enabled on a profile 287 */ 288 private void ruleEnabled(RulesProfile profile, ActiveRule newActiveRule, String userName) { 289 incrementProfileVersionIfNeeded(profile); 290 ActiveRuleChange rc = new ActiveRuleChange(userName, profile, newActiveRule.getRule()); 291 rc.setEnabled(true); 292 rc.setNewSeverity(newActiveRule.getSeverity()); 293 if (newActiveRule.getRule().getParams() != null) { 294 for (RuleParam p : newActiveRule.getRule().getParams()) { 295 String newParam = newActiveRule.getParameter(p.getKey()); 296 if (newParam != null) { 297 rc.setParameterChange(p.getKey(), null, newParam); 298 } 299 } 300 } 301 getSession().saveWithoutFlush(rc); 302 } 303 304 /** 305 * Deal with creation of ActiveRuleChange item when a rule is disabled on a profile 306 */ 307 private void ruleDisabled(RulesProfile profile, ActiveRule disabledRule, String userName) { 308 incrementProfileVersionIfNeeded(profile); 309 ActiveRuleChange rc = new ActiveRuleChange(userName, profile, disabledRule.getRule()); 310 rc.setEnabled(false); 311 rc.setOldSeverity(disabledRule.getSeverity()); 312 if (disabledRule.getRule().getParams() != null) { 313 for (RuleParam p : disabledRule.getRule().getParams()) { 314 String oldParam = disabledRule.getParameter(p.getKey()); 315 if (oldParam != null) { 316 rc.setParameterChange(p.getKey(), oldParam, null); 317 } 318 } 319 } 320 getSession().saveWithoutFlush(rc); 321 } 322 323 private void activateOrChange(RulesProfile profile, ActiveRule parentActiveRule, String userName) { 324 ActiveRule oldActiveRule = profile.getActiveRule(parentActiveRule.getRule()); 325 if (oldActiveRule != null) { 326 if (oldActiveRule.isInherited()) { 327 removeActiveRule(profile, oldActiveRule); 328 } else { 329 oldActiveRule.setInheritance(ActiveRule.OVERRIDES); 330 getSession().saveWithoutFlush(oldActiveRule); 331 return; // no need to change in children 332 } 333 } 334 ActiveRule newActiveRule = (ActiveRule) parentActiveRule.clone(); 335 newActiveRule.setRulesProfile(profile); 336 newActiveRule.setInheritance(ActiveRule.INHERITED); 337 profile.addActiveRule(newActiveRule); 338 getSession().saveWithoutFlush(newActiveRule); 339 340 if (oldActiveRule != null) { 341 ruleChanged(profile, oldActiveRule, newActiveRule, userName); 342 } else { 343 ruleEnabled(profile, newActiveRule, userName); 344 } 345 346 for (RulesProfile child : getChildren(profile)) { 347 activateOrChange(child, newActiveRule, userName); 348 } 349 } 350 351 private void deactivate(RulesProfile profile, Rule rule, String userName) { 352 ActiveRule activeRule = profile.getActiveRule(rule); 353 if (activeRule != null) { 354 if (activeRule.isInherited()) { 355 ruleDisabled(profile, activeRule, userName); 356 removeActiveRule(profile, activeRule); 357 } else { 358 activeRule.setInheritance(null); 359 getSession().saveWithoutFlush(activeRule); 360 return; // no need to change in children 361 } 362 363 for (RulesProfile child : getChildren(profile)) { 364 deactivate(child, rule, userName); 365 } 366 } 367 } 368 369 private List<RulesProfile> getChildren(int parentId) { 370 RulesProfile parent = getSession().getEntity(RulesProfile.class, parentId); 371 return getChildren(parent); 372 } 373 374 private List<RulesProfile> getChildren(RulesProfile parent) { 375 return getSession().getResults(RulesProfile.class, 376 "language", parent.getLanguage(), 377 "parentName", parent.getName(), 378 "provided", false, 379 "enabled", true); 380 } 381 382 private void removeActiveRule(RulesProfile profile, ActiveRule activeRule) { 383 profile.removeActiveRule(activeRule); 384 getSession().removeWithoutFlush(activeRule); 385 } 386 387 RulesProfile getProfile(String language, String name) { 388 return getSession().getSingleResult(RulesProfile.class, 389 "language", language, 390 "name", name, 391 "enabled", true); 392 } 393 394 RulesProfile getParentProfile(RulesProfile profile) { 395 if (profile.getParentName() == null) { 396 return null; 397 } 398 return getProfile(profile.getLanguage(), profile.getParentName()); 399 } 400 401 }