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.database.model;
021    
022    import org.apache.commons.lang.builder.ToStringBuilder;
023    import org.hibernate.annotations.Cache;
024    import org.hibernate.annotations.CacheConcurrencyStrategy;
025    import org.sonar.api.database.BaseIdentifiable;
026    import org.sonar.api.database.DatabaseSession;
027    import org.sonar.api.measures.Measure;
028    import org.sonar.api.measures.Metric;
029    import org.sonar.api.measures.RuleMeasure;
030    import org.sonar.api.rules.Rule;
031    import org.sonar.api.rules.RulePriority;
032    
033    import java.util.ArrayList;
034    import java.util.Date;
035    import java.util.List;
036    import javax.persistence.*;
037    
038    @Entity
039    @Table(name = "project_measures")
040    public class MeasureModel extends BaseIdentifiable implements Cloneable {
041    
042      public static final int TEXT_VALUE_LENGTH = 96;
043    
044      @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20)
045      private Double value = 0.0;
046    
047      @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH)
048      private String textValue;
049    
050      @Column(name = "tendency", updatable = true, nullable = true)
051      private Integer tendency;
052    
053      @ManyToOne(fetch = FetchType.EAGER)
054      @JoinColumn(name = "metric_id")
055      @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
056      private Metric metric;
057    
058      @Column(name = "snapshot_id", updatable = true, nullable = true)
059      private Integer snapshotId;
060    
061      @Column(name = "project_id", updatable = true, nullable = true)
062      private Integer projectId;
063    
064      @Column(name = "description", updatable = true, nullable = true, length = 4000)
065      private String description;
066    
067      @Temporal(TemporalType.TIMESTAMP)
068      @Column(name = "measure_date", updatable = true, nullable = true)
069      private Date measureDate;
070    
071      @ManyToOne(fetch = FetchType.LAZY)
072      @JoinColumn(name = "rule_id")
073      @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
074      private Rule rule;
075    
076      @Column(name = "rules_category_id")
077      private Integer rulesCategoryId;
078    
079      @Column(name = "rule_priority", updatable = false, nullable = true)
080      @Enumerated(EnumType.ORDINAL)
081      private RulePriority rulePriority;
082    
083      @Column(name = "alert_status", updatable = true, nullable = true, length = 5)
084      private String alertStatus;
085    
086      @Column(name = "alert_text", updatable = true, nullable = true, length = 4000)
087      private String alertText;
088    
089      @Column(name = "diff_value_1", updatable = true, nullable = true)
090      private Double diffValue1;
091    
092      @Column(name = "diff_value_2", updatable = true, nullable = true)
093      private Double diffValue2;
094    
095      @Column(name = "diff_value_3", updatable = true, nullable = true)
096      private Double diffValue3;
097    
098      @Column(name = "url", updatable = true, nullable = true, length = 2000)
099      private String url;
100    
101      @OneToMany(mappedBy = "measure", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
102      private List<MeasureData> measureData = new ArrayList<MeasureData>();
103    
104      public MeasureModel(Metric metric, Double val) {
105        if (val.isNaN() || val.isInfinite()) {
106          throw new IllegalArgumentException("Measure value is NaN. Metric=" + metric);
107        }
108        this.metric = metric;
109        this.value = val;
110      }
111    
112      public MeasureModel(Metric metric, Metric.Level level) {
113        this.metric = metric;
114        if (level != null) {
115          this.textValue = level.toString();
116        }
117      }
118    
119      public MeasureModel(Metric metric, String val) {
120        this.metric = metric;
121        setData(val);
122      }
123    
124      public MeasureModel() {
125      }
126    
127      public Double getValue() {
128        return value;
129      }
130    
131      public String getDescription() {
132        return description;
133      }
134    
135      public void setDescription(String description) {
136        this.description = description;
137      }
138    
139      public MeasureModel setValue(Double value) throws IllegalArgumentException {
140        if (value != null && (value.isNaN() || value.isInfinite())) {
141          throw new IllegalArgumentException();
142        }
143        this.value = value;
144        return this;
145      }
146    
147      public Metric.Level getLevelValue() {
148        if (textValue != null) {
149          return Metric.Level.valueOf(textValue);
150        }
151        return null;
152      }
153    
154      /**
155       * Use getData() instead
156       */
157      public String getTextValue() {
158        return textValue;
159      }
160    
161      /**
162       * Use setData() instead
163       */
164      public void setTextValue(String textValue) {
165        this.textValue = textValue;
166      }
167    
168      public Integer getTendency() {
169        return tendency;
170      }
171    
172      public boolean isRuleMeasure() {
173        return rule != null || rulePriority != null || rulesCategoryId != null;
174      }
175    
176      public MeasureModel setTendency(Integer tendency) {
177        this.tendency = tendency;
178        return this;
179      }
180    
181      public Metric getMetric() {
182        return metric;
183      }
184    
185      public void setMetric(Metric metric) {
186        this.metric = metric;
187      }
188    
189      public Integer getSnapshotId() {
190        return snapshotId;
191      }
192    
193      public MeasureModel setSnapshotId(Integer snapshotId) {
194        this.snapshotId = snapshotId;
195        return this;
196      }
197    
198      public Rule getRule() {
199        return rule;
200      }
201    
202      public MeasureModel setRule(Rule rule) {
203        this.rule = rule;
204        return this;
205      }
206    
207      public Integer getRulesCategoryId() {
208        return rulesCategoryId;
209      }
210    
211      public MeasureModel setRulesCategoryId(Integer id) {
212        this.rulesCategoryId = id;
213        return this;
214      }
215    
216      public RulePriority getRulePriority() {
217        return rulePriority;
218      }
219    
220      public void setRulePriority(RulePriority rulePriority) {
221        this.rulePriority = rulePriority;
222      }
223    
224      public Integer getProjectId() {
225        return projectId;
226      }
227    
228      public void setProjectId(Integer projectId) {
229        this.projectId = projectId;
230      }
231    
232      public Date getMeasureDate() {
233        return measureDate;
234      }
235    
236      public MeasureModel setMeasureDate(Date measureDate) {
237        this.measureDate = measureDate;
238        return this;
239      }
240    
241      public Metric.Level getAlertStatus() {
242        if (alertStatus == null) {
243          return null;
244        }
245        return Metric.Level.valueOf(alertStatus);
246      }
247    
248      public MeasureModel setAlertStatus(Metric.Level level) {
249        if (level != null) {
250          this.alertStatus = level.toString();
251        } else {
252          this.alertStatus = null;
253        }
254        return this;
255      }
256    
257      public String getData() {
258        if (this.textValue != null) {
259          return this.textValue;
260        }
261        if (metric.isDataType() && !measureData.isEmpty()) {
262          return measureData.get(0).getText();
263        }
264        return null;
265      }
266    
267      public void setData(String data) {
268        if (data == null) {
269          this.textValue = null;
270          measureData.clear();
271    
272        } else {
273          if (data.length() > TEXT_VALUE_LENGTH) {
274            measureData.clear();
275            measureData.add(new MeasureData(this, data));
276    
277          } else {
278            this.textValue = data;
279          }
280        }
281      }
282    
283      /**
284       * Use getData() instead
285       */
286      public MeasureData getMeasureData() {
287        if (!measureData.isEmpty()) {
288          return measureData.get(0);
289        }
290        return null;
291      }
292    
293      /**
294       * Use setData() instead
295       */
296      //@Deprecated
297      public void setMeasureData(MeasureData data) {
298        measureData.clear();
299        if (data != null) {
300          this.measureData.add(data);
301        }
302      }
303    
304      public String getAlertText() {
305        return alertText;
306      }
307    
308      public void setAlertText(String alertText) {
309        this.alertText = alertText;
310      }
311    
312      public String getUrl() {
313        return url;
314      }
315    
316      public void setUrl(String url) {
317        this.url = url;
318      }
319    
320      @Override
321      public String toString() {
322        return new ToStringBuilder(this).
323            append("value", value).
324            append("metric", metric).
325            toString();
326      }
327    
328      public Integer getRuleId() {
329        if (getRule() != null) {
330          return getRule().getId();
331        }
332        return null;
333      }
334    
335      public Double getDiffValue1() {
336        return diffValue1;
337      }
338    
339      public void setDiffValue1(Double diffValue1) {
340        this.diffValue1 = diffValue1;
341      }
342    
343      public Double getDiffValue2() {
344        return diffValue2;
345      }
346    
347      public void setDiffValue2(Double diffValue2) {
348        this.diffValue2 = diffValue2;
349      }
350    
351      public Double getDiffValue3() {
352        return diffValue3;
353      }
354    
355      public void setDiffValue3(Double diffValue3) {
356        this.diffValue3 = diffValue3;
357      }
358    
359      public MeasureModel save(DatabaseSession session) {
360        this.metric = session.reattach(Metric.class, metric.getId());
361        MeasureData data = getMeasureData();
362        setMeasureData(null);
363        session.save(this);
364    
365        if (data != null) {
366          data.setMeasure(session.getEntity(MeasureModel.class, getId()));
367          data.setSnapshotId(snapshotId);
368          session.save(data);
369          setMeasureData(data);
370        }
371        return this;
372      }
373    
374      @Override
375      public Object clone() {
376        MeasureModel clone = new MeasureModel();
377        clone.setMetric(getMetric());
378        clone.setDescription(getDescription());
379        clone.setTextValue(getTextValue());
380        clone.setAlertStatus(getAlertStatus());
381        clone.setAlertText(getAlertText());
382        clone.setTendency(getTendency());
383        clone.setDiffValue1(getDiffValue1());
384        clone.setDiffValue2(getDiffValue2());
385        clone.setDiffValue3(getDiffValue3());
386        clone.setValue(getValue());
387        clone.setRulesCategoryId(getRulesCategoryId());
388        clone.setRulePriority(getRulePriority());
389        clone.setRule(getRule());
390        clone.setSnapshotId(getSnapshotId());
391        clone.setMeasureDate(getMeasureDate());
392        clone.setUrl(getUrl());
393        return clone;
394      }
395    
396      public static MeasureModel build(Measure measure) {
397        return build(measure, new MeasureModel());
398      }
399    
400      public static MeasureModel build(Measure measure, MeasureModel merge) {
401        merge.setMetric(measure.getMetric());
402        merge.setDescription(measure.getDescription());
403        merge.setData(measure.getData());
404        merge.setAlertStatus(measure.getAlertStatus());
405        merge.setAlertText(measure.getAlertText());
406        merge.setTendency(measure.getTendency());
407        merge.setDiffValue1(measure.getDiffValue1());
408        merge.setDiffValue2(measure.getDiffValue2());
409        merge.setDiffValue3(measure.getDiffValue3());
410        merge.setUrl(measure.getUrl());
411        if (measure.getValue() != null) {
412          merge.setValue(measure.getValue().doubleValue());
413        } else {
414          merge.setValue(null);
415        }
416        if (measure instanceof RuleMeasure) {
417          RuleMeasure ruleMeasure = (RuleMeasure) measure;
418          merge.setRulesCategoryId(ruleMeasure.getRuleCategory());
419          merge.setRulePriority(ruleMeasure.getRulePriority());
420          merge.setRule(ruleMeasure.getRule());
421        }
422        return merge;
423      }
424    
425      public Measure toMeasure() {
426        Measure measure;
427        if (isRuleMeasure()) {
428          measure = new RuleMeasure(getMetric(), getRule(), getRulePriority(), getRulesCategoryId());
429        } else {
430          measure = new Measure(getMetric());
431        }
432        measure.setId(getId());
433        measure.setDescription(getDescription());
434        measure.setValue(getValue());
435        measure.setData(getData());
436        measure.setAlertStatus(getAlertStatus());
437        measure.setAlertText(getAlertText());
438        measure.setTendency(getTendency());
439        measure.setDiffValue1(getDiffValue1());
440        measure.setDiffValue2(getDiffValue2());
441        measure.setDiffValue3(getDiffValue3());
442        measure.setUrl(getUrl());
443        return measure;
444      }
445    
446      public static List<Measure> toMeasures(List<MeasureModel> models) {
447        List<Measure> result = new ArrayList<Measure>();
448        for (MeasureModel model : models) {
449          if (model != null) {
450            result.add(model.toMeasure());
451          }
452        }
453        return result;
454      }
455    }