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 org.apache.commons.lang.StringUtils;
023    import org.apache.commons.lang.builder.ToStringBuilder;
024    import org.apache.commons.lang.builder.ToStringStyle;
025    import org.hibernate.annotations.Sort;
026    import org.hibernate.annotations.SortType;
027    import org.sonar.api.rules.Rule;
028    
029    import java.util.*;
030    import javax.persistence.*;
031    
032    /**
033     * @since 2.3
034     */
035    @Entity
036    @Table(name = "characteristics")
037    public final class Characteristic implements Comparable<Characteristic> {
038    
039      public static final int ROOT_DEPTH = 1;
040    
041      @Id
042      @Column(name = "id")
043      @GeneratedValue
044      private Integer id;
045    
046      @Column(name = "kee", nullable = true, length = 100)
047      private String key;
048    
049      @Column(name = "name", nullable = true, length = 100)
050      private String name;
051    
052      @Column(name = "depth")
053      private int depth=ROOT_DEPTH;
054    
055      @Column(name = "characteristic_order")
056      private int order=0;
057    
058      @ManyToOne(fetch = FetchType.EAGER)
059      @JoinColumn(name = "quality_model_id")
060      private Model model;
061    
062      @ManyToOne(fetch = FetchType.EAGER)
063      @JoinColumn(name = "rule_id")
064      private Rule rule;
065    
066    
067      @ManyToMany
068      @JoinTable(
069          name = "characteristic_edges",
070          joinColumns = @JoinColumn(name = "child_id", referencedColumnName = "id"),
071          inverseJoinColumns = @JoinColumn(name = "parent_id",
072              referencedColumnName = "id")
073      )
074      private List<Characteristic> parents = new ArrayList<Characteristic>();
075    
076      @Sort(type = SortType.NATURAL)
077      @ManyToMany(mappedBy = "parents", cascade = CascadeType.ALL)
078      private List<Characteristic> children = new ArrayList<Characteristic>();
079    
080      Characteristic() {
081      }
082    
083      public Integer getId() {
084        return id;
085      }
086    
087      Characteristic setId(Integer id) {
088        this.id = id;
089        return this;
090      }
091    
092      public String getKey() {
093        return key;
094      }
095    
096      Characteristic setKey(String s) {
097        this.key = StringUtils.trimToEmpty(s);
098        return this;
099      }
100    
101      public String getName() {
102        return name;
103      }
104    
105      Characteristic setName(String s, boolean asKey) {
106        this.name = StringUtils.trimToEmpty(s);
107        if (asKey) {
108          this.key = StringUtils.upperCase(this.name);
109          this.key = StringUtils.replaceChars(this.key, ' ', '_');
110        }
111        return this;
112      }
113    
114      public Model getModel() {
115        return model;
116      }
117    
118      Characteristic setModel(Model model) {
119        this.model = model;
120        return this;
121      }
122    
123      public Rule getRule() {
124        return rule;
125      }
126    
127      public Characteristic setRule(Rule r) {
128        this.rule = r;
129        return this;
130      }
131    
132      public Characteristic addChildren(Characteristic... list) {
133        if (list != null) {
134          for (Characteristic c : list) {
135            addChild(c);
136          }
137        }
138        return this;
139      }
140      
141      public Characteristic addChild(Characteristic child) {
142        propagateDepth(child, depth+1);
143        child.addParents(this);
144        child.setModel(model);
145        children.add(child);
146        return this;
147      }
148    
149      private static void propagateDepth(Characteristic characteristic, int depth) {
150        characteristic.setDepth(depth);
151        for (Characteristic child : characteristic.getChildren()) {
152          propagateDepth(child, depth+1);
153        }
154      }
155    
156      Characteristic addParents(Characteristic... pc) {
157        if (pc!=null) {
158          Collections.addAll(this.parents, pc);
159        }
160        return this;
161      }
162    
163      public List<Characteristic> getParents() {
164        return parents;
165      }
166    
167      public Characteristic getParent(String name) {
168        for (Characteristic parent : parents) {
169          if (StringUtils.equals(parent.getName(), name)) {
170            return parent;
171          }
172        }
173        return null;
174      }
175    
176      /**
177       * Children sorted by insertion order
178       */
179      public List<Characteristic> getChildren() {
180        return children;
181      }
182    
183      public Characteristic getChild(String name) {
184        for (Characteristic child : children) {
185          if (StringUtils.equals(child.getName(), name)) {
186            return child;
187          }
188        }
189        return null;
190      }
191    
192      public int getDepth() {
193        return depth;
194      }
195    
196      public boolean isRoot() {
197        return depth==ROOT_DEPTH;
198      }
199    
200      Characteristic setDepth(int i) {
201        this.depth = i;
202        return this;
203      }
204    
205      public int getOrder() {
206        return order;
207      }
208    
209      Characteristic setOrder(int i) {
210        this.order = i;
211        return this;
212      }
213    
214      @Override
215      public boolean equals(Object o) {
216        if (this == o) {
217          return true;
218        }
219        if (o == null || getClass() != o.getClass()) {
220          return false;
221        }
222    
223        Characteristic that = (Characteristic) o;
224        if (key != null ? !key.equals(that.key) : that.key != null) {
225          return false;
226        }
227        if (rule != null ? !rule.equals(that.rule) : that.rule != null) {
228          return false;
229        }
230        return true;
231      }
232    
233      @Override
234      public int hashCode() {
235        int result = key != null ? key.hashCode() : 0;
236        result = 31 * result + (rule != null ? rule.hashCode() : 0);
237        return result;
238      }
239    
240      @Override
241      public String toString() {
242        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
243            .append("key", key)
244            .append("name", name)
245            .append("rule", rule)
246            .toString();
247      }
248    
249      public int compareTo(Characteristic o) {
250        if (equals(o)) {
251          return 0;
252        }
253        return order - o.order;
254      }
255    }