001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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      public Characteristic setName(String s, boolean asKey) {
119        this.name = StringUtils.trimToNull(s);
120        if (asKey) {
121          this.key = StringUtils.upperCase(this.name);
122          this.key = StringUtils.replaceChars(this.key, ' ', '_');
123        }
124        return this;
125      }
126    
127      public Model getModel() {
128        return model;
129      }
130    
131      Characteristic setModel(Model model) {
132        this.model = model;
133        return this;
134      }
135    
136      public Rule getRule() {
137        return rule;
138      }
139    
140      public boolean hasRule() {
141        return rule!=null;
142      }
143    
144      public Characteristic setRule(Rule r) {
145        this.rule = r;
146        return this;
147      }
148    
149      public Boolean getEnabled() {
150        return enabled;
151      }
152    
153      public Characteristic setEnabled(Boolean b) {
154        this.enabled = b;
155        return this;
156      }
157    
158      public Characteristic addChildren(Characteristic... list) {
159        if (list != null) {
160          for (Characteristic c : list) {
161            addChild(c);
162          }
163        }
164        return this;
165      }
166    
167      public Characteristic addChild(Characteristic child) {
168        propagateDepth(child, depth + 1);
169        child.addParents(this);
170        child.setModel(model);
171        children.add(child);
172        return this;
173      }
174    
175      Characteristic removeChild(Characteristic child) {
176        children.remove(child);
177        return this;
178      }
179    
180      private static void propagateDepth(Characteristic characteristic, int depth) {
181        characteristic.setDepth(depth);
182        for (Characteristic child : characteristic.getChildren()) {
183          propagateDepth(child, depth + 1);
184        }
185      }
186    
187      Characteristic addParents(Characteristic... pc) {
188        if (pc != null) {
189          Collections.addAll(this.parents, pc);
190        }
191        return this;
192      }
193    
194      public List<Characteristic> getParents() {
195        return parents;
196      }
197    
198      public Characteristic getParent(String name) {
199        for (Characteristic parent : parents) {
200          if (StringUtils.equals(parent.getName(), name)) {
201            return parent;
202          }
203        }
204        return null;
205      }
206    
207      /**
208       * Children sorted by insertion order
209       */
210      public List<Characteristic> getChildren() {
211        return children;
212      }
213    
214      public Characteristic getChild(String name) {
215        for (Characteristic child : children) {
216          if (StringUtils.equals(child.getName(), name)) {
217            return child;
218          }
219        }
220        return null;
221      }
222    
223      public int getDepth() {
224        return depth;
225      }
226    
227      public boolean isRoot() {
228        return depth == ROOT_DEPTH;
229      }
230    
231      Characteristic setDepth(int i) {
232        this.depth = i;
233        return this;
234      }
235    
236      public int getOrder() {
237        return order;
238      }
239    
240      Characteristic setOrder(int i) {
241        this.order = i;
242        return this;
243      }
244    
245      public String getDescription() {
246        return description;
247      }
248    
249      public Characteristic setDescription(String s) {
250        this.description = s;
251        return this;
252      }
253    
254      public CharacteristicProperty setProperty(String key, String value) {
255        return addProperty(CharacteristicProperty.create(key).setTextValue(value));
256      }
257    
258      public CharacteristicProperty setProperty(String key, Double value) {
259        return addProperty(CharacteristicProperty.create(key).setValue(value));
260      }
261    
262      public CharacteristicProperty addProperty(CharacteristicProperty property) {
263        property.setCharacteristic(this);
264        properties.add(property);
265        return property;
266      }
267    
268      public CharacteristicProperty getProperty(String key) {
269        for (CharacteristicProperty property : properties) {
270          if (StringUtils.equals(key, property.getKey())) {
271            return property;
272          }
273        }
274        return null;
275      }
276    
277      public String getPropertyTextValue(String key, String defaultValue) {
278        CharacteristicProperty property = getProperty(key);
279        String value = property != null ? property.getTextValue() : null;
280        return StringUtils.defaultIfEmpty(value, defaultValue);
281      }
282    
283      public Double getPropertyValue(String key, Double defaultValue) {
284        CharacteristicProperty property = getProperty(key);
285        Double value = (property != null ? property.getValue() : null);
286        return value==null ? defaultValue : value;
287      }
288    
289      public List<CharacteristicProperty> getProperties() {
290        return properties;
291      }
292    
293      @Override
294      public boolean equals(Object o) {
295        if (this == o) {
296          return true;
297        }
298        if (o == null || getClass() != o.getClass()) {
299          return false;
300        }
301    
302        Characteristic that = (Characteristic) o;
303        if (key != null ? !key.equals(that.key) : that.key != null) {
304          return false;
305        }
306        if (rule != null ? !rule.equals(that.rule) : that.rule != null) {
307          return false;
308        }
309        return true;
310      }
311    
312      @Override
313      public int hashCode() {
314        int result = key != null ? key.hashCode() : 0;
315        result = 31 * result + (rule != null ? rule.hashCode() : 0);
316        return result;
317      }
318    
319      @Override
320      public String toString() {
321        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
322            .append("key", key)
323            .append("name", name)
324            .append("rule", rule)
325            .append("description", description)
326            .toString();
327      }
328    
329      public int compareTo(Characteristic o) {
330        if (equals(o)) {
331          return 0;
332        }
333        return order - o.order;
334      }
335    
336      public static Characteristic create() {
337        return new Characteristic();
338      }
339    
340      public static Characteristic createByName(String name) {
341        return new Characteristic().setName(name, true);
342      }
343    
344      public static Characteristic createByKey(String key, String name) {
345        return new Characteristic().setKey(key).setName(name, false);
346      }
347    
348      public static Characteristic createByRule(Rule rule) {
349        return new Characteristic().setRule(rule);
350      }
351    }