001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube 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 * SonarQube 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 License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 package org.sonar.api.qualitymodel; 021 022 import com.google.common.collect.Lists; 023 import org.apache.commons.lang.StringUtils; 024 import org.apache.commons.lang.builder.ToStringBuilder; 025 import org.apache.commons.lang.builder.ToStringStyle; 026 import org.hibernate.annotations.Sort; 027 import org.hibernate.annotations.SortType; 028 import org.sonar.api.rules.Rule; 029 030 import javax.persistence.*; 031 032 import java.util.Collections; 033 import java.util.List; 034 035 /** 036 * @since 2.3 037 */ 038 @Entity 039 @Table(name = "characteristics") 040 public final class Characteristic implements Comparable<Characteristic> { 041 042 public static final int ROOT_DEPTH = 1; 043 044 @Id 045 @Column(name = "id") 046 @GeneratedValue 047 private Integer id; 048 049 @Column(name = "kee", nullable = true, length = 100) 050 private String key; 051 052 @Column(name = "name", nullable = true, length = 100) 053 private String name; 054 055 @Column(name = "depth") 056 private int depth = ROOT_DEPTH; 057 058 @Column(name = "characteristic_order") 059 private int order = 0; 060 061 @ManyToOne(fetch = FetchType.EAGER) 062 @JoinColumn(name = "quality_model_id") 063 private Model model; 064 065 @ManyToOne(fetch = FetchType.EAGER) 066 @JoinColumn(name = "rule_id") 067 private Rule rule; 068 069 @Column(name = "description", nullable = true, length = 4000) 070 private String description; 071 072 @Column(name = "enabled", updatable = true, nullable = true) 073 private Boolean enabled = Boolean.TRUE; 074 075 @ManyToMany 076 @JoinTable( 077 name = "characteristic_edges", 078 joinColumns = @JoinColumn(name = "child_id", referencedColumnName = "id"), 079 inverseJoinColumns = @JoinColumn(name = "parent_id", 080 referencedColumnName = "id") 081 ) 082 private List<Characteristic> parents = Lists.newArrayList(); 083 084 @Sort(type = SortType.NATURAL) 085 @ManyToMany(mappedBy = "parents", cascade = CascadeType.ALL) 086 private List<Characteristic> children = Lists.newArrayList(); 087 088 @OneToMany(mappedBy = "characteristic", fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE}) 089 private List<CharacteristicProperty> properties = Lists.newArrayList(); 090 091 Characteristic() { 092 } 093 094 public Integer getId() { 095 return id; 096 } 097 098 Characteristic setId(Integer id) { 099 this.id = id; 100 return this; 101 } 102 103 public String getKey() { 104 return key; 105 } 106 107 public Characteristic setKey(String s) { 108 this.key = StringUtils.trimToNull(s); 109 return this; 110 } 111 112 public String getName() { 113 return name; 114 } 115 116 public Characteristic setName(String s) { 117 return setName(s, false); 118 } 119 120 public Characteristic setName(String s, boolean asKey) { 121 this.name = StringUtils.trimToNull(s); 122 if (asKey) { 123 this.key = StringUtils.upperCase(this.name); 124 this.key = StringUtils.replaceChars(this.key, ' ', '_'); 125 } 126 return this; 127 } 128 129 public Model getModel() { 130 return model; 131 } 132 133 Characteristic setModel(Model model) { 134 this.model = model; 135 return this; 136 } 137 138 public Rule getRule() { 139 return rule; 140 } 141 142 public boolean hasRule() { 143 return rule != null; 144 } 145 146 public Characteristic setRule(Rule r) { 147 this.rule = r; 148 return this; 149 } 150 151 public Boolean getEnabled() { 152 return enabled; 153 } 154 155 public Characteristic setEnabled(Boolean b) { 156 this.enabled = b; 157 return this; 158 } 159 160 public Characteristic addChildren(Characteristic... list) { 161 if (list != null) { 162 for (Characteristic c : list) { 163 addChild(c); 164 } 165 } 166 return this; 167 } 168 169 public Characteristic addChild(Characteristic child) { 170 propagateDepth(child, depth + 1); 171 child.addParents(this); 172 child.setModel(model); 173 children.add(child); 174 return this; 175 } 176 177 Characteristic removeChild(Characteristic child) { 178 children.remove(child); 179 return this; 180 } 181 182 private static void propagateDepth(Characteristic characteristic, int depth) { 183 characteristic.setDepth(depth); 184 for (Characteristic child : characteristic.getChildren()) { 185 propagateDepth(child, depth + 1); 186 } 187 } 188 189 Characteristic addParents(Characteristic... pc) { 190 if (pc != null) { 191 Collections.addAll(this.parents, pc); 192 } 193 return this; 194 } 195 196 public List<Characteristic> getParents() { 197 return parents; 198 } 199 200 public Characteristic getParent(String name) { 201 for (Characteristic parent : parents) { 202 if (StringUtils.equals(parent.getName(), name)) { 203 return parent; 204 } 205 } 206 return null; 207 } 208 209 /** 210 * Enabled children sorted by insertion order 211 */ 212 public List<Characteristic> getChildren() { 213 return getChildren(true); 214 } 215 216 /** 217 * Enabled children sorted by insertion order 218 */ 219 public List<Characteristic> getChildren(boolean onlyEnabled) { 220 if (onlyEnabled) { 221 return children; 222 } 223 List<Characteristic> result = Lists.newArrayList(); 224 for (Characteristic child : children) { 225 if (child.getEnabled()) { 226 result.add(child); 227 } 228 } 229 return result; 230 } 231 232 public Characteristic getChild(String name) { 233 for (Characteristic child : children) { 234 if (StringUtils.equals(child.getName(), name)) { 235 return child; 236 } 237 } 238 return null; 239 } 240 241 public int getDepth() { 242 return depth; 243 } 244 245 public boolean isRoot() { 246 return depth == ROOT_DEPTH; 247 } 248 249 Characteristic setDepth(int i) { 250 this.depth = i; 251 return this; 252 } 253 254 public int getOrder() { 255 return order; 256 } 257 258 Characteristic setOrder(int i) { 259 this.order = i; 260 return this; 261 } 262 263 public String getDescription() { 264 return description; 265 } 266 267 public Characteristic setDescription(String s) { 268 this.description = s; 269 return this; 270 } 271 272 public CharacteristicProperty setProperty(String key, String value) { 273 return addProperty(CharacteristicProperty.create(key).setTextValue(value)); 274 } 275 276 public CharacteristicProperty setProperty(String key, Double value) { 277 return addProperty(CharacteristicProperty.create(key).setValue(value)); 278 } 279 280 public CharacteristicProperty addProperty(CharacteristicProperty property) { 281 property.setCharacteristic(this); 282 properties.add(property); 283 return property; 284 } 285 286 public CharacteristicProperty getProperty(String key) { 287 for (CharacteristicProperty property : properties) { 288 if (StringUtils.equals(key, property.getKey())) { 289 return property; 290 } 291 } 292 return null; 293 } 294 295 public String getPropertyTextValue(String key, String defaultValue) { 296 CharacteristicProperty property = getProperty(key); 297 String value = property != null ? property.getTextValue() : null; 298 return StringUtils.defaultIfEmpty(value, defaultValue); 299 } 300 301 public Double getPropertyValue(String key, Double defaultValue) { 302 CharacteristicProperty property = getProperty(key); 303 Double value = property != null ? property.getValue() : null; 304 return value == null ? defaultValue : value; 305 } 306 307 public List<CharacteristicProperty> getProperties() { 308 return properties; 309 } 310 311 @Override 312 public boolean equals(Object o) { 313 if (this == o) { 314 return true; 315 } 316 if (o == null || getClass() != o.getClass()) { 317 return false; 318 } 319 320 Characteristic that = (Characteristic) o; 321 if (key != null ? !key.equals(that.key) : that.key != null) { 322 return false; 323 } 324 if (rule != null ? !rule.equals(that.rule) : that.rule != null) { 325 return false; 326 } 327 return true; 328 } 329 330 @Override 331 public int hashCode() { 332 int result = key != null ? key.hashCode() : 0; 333 result = 31 * result + (rule != null ? rule.hashCode() : 0); 334 return result; 335 } 336 337 @Override 338 public String toString() { 339 return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 340 .append("key", key) 341 .append("name", name) 342 .append("rule", rule) 343 .append("description", description) 344 .toString(); 345 } 346 347 public int compareTo(Characteristic o) { 348 if (equals(o)) { 349 return 0; 350 } 351 return order - o.order; 352 } 353 354 public static Characteristic create() { 355 return new Characteristic(); 356 } 357 358 public static Characteristic createByName(String name) { 359 return new Characteristic().setName(name, true); 360 } 361 362 public static Characteristic createByKey(String key, String name) { 363 return new Characteristic().setKey(key).setName(name, false); 364 } 365 366 public static Characteristic createByRule(Rule rule) { 367 return new Characteristic().setRule(rule); 368 } 369 }