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