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 }