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 */
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 import java.util.Collections;
032 import java.util.List;
033
034 /**
035 * @since 2.3
036 */
037 @Entity
038 @Table(name = "characteristics")
039 public 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 }