001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 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.database.model;
021    
022    import org.apache.commons.lang.builder.ReflectionToStringBuilder;
023    import org.apache.commons.lang.builder.ToStringBuilder;
024    import org.apache.commons.lang.builder.ToStringStyle;
025    import org.sonar.api.database.DatabaseSession;
026    import org.sonar.api.measures.Metric;
027    import org.sonar.api.qualitymodel.Characteristic;
028    import org.sonar.api.rules.RulePriority;
029    
030    import javax.persistence.*;
031    import java.util.ArrayList;
032    import java.util.Date;
033    import java.util.List;
034    
035    /**
036     * This class is the Hibernate model to store a measure in the DB
037     */
038    @Entity
039    @Table(name = "project_measures")
040    public class MeasureModel implements Cloneable {
041    
042      public static final int TEXT_VALUE_LENGTH = 96;
043    
044      @Id
045      @Column(name = "id")
046      @GeneratedValue
047      private Long id;
048    
049      @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20)
050      private Double value = 0.0;
051    
052      @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH)
053      private String textValue;
054    
055      @Column(name = "tendency", updatable = true, nullable = true)
056      private Integer tendency;
057    
058      @Column(name = "metric_id", updatable = false, nullable = false)
059      private Integer metricId;
060    
061      @Column(name = "snapshot_id", updatable = true, nullable = true)
062      private Integer snapshotId;
063    
064      @Column(name = "project_id", updatable = true, nullable = true)
065      private Integer projectId;
066    
067      @Column(name = "description", updatable = true, nullable = true, length = 4000)
068      private String description;
069    
070      @Temporal(TemporalType.TIMESTAMP)
071      @Column(name = "measure_date", updatable = true, nullable = true)
072      private Date measureDate;
073    
074      @Column(name = "rule_id", updatable = true, nullable = true)
075      private Integer ruleId;
076    
077      /**
078       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
079       */
080      @Deprecated
081      @Column(name = "rules_category_id", nullable = true)
082      private Integer rulesCategoryId;
083    
084      @Column(name = "rule_priority", updatable = false, nullable = true)
085      @Enumerated(EnumType.ORDINAL)
086      private RulePriority rulePriority;
087    
088      @Column(name = "alert_status", updatable = true, nullable = true, length = 5)
089      private String alertStatus;
090    
091      @Column(name = "alert_text", updatable = true, nullable = true, length = 4000)
092      private String alertText;
093    
094      @Column(name = "variation_value_1", updatable = true, nullable = true)
095      private Double variationValue1;
096    
097      @Column(name = "variation_value_2", updatable = true, nullable = true)
098      private Double variationValue2;
099    
100      @Column(name = "variation_value_3", updatable = true, nullable = true)
101      private Double variationValue3;
102    
103      @Column(name = "variation_value_4", updatable = true, nullable = true)
104      private Double variationValue4;
105    
106      @Column(name = "variation_value_5", updatable = true, nullable = true)
107      private Double variationValue5;
108    
109      @Column(name = "url", updatable = true, nullable = true, length = 2000)
110      private String url;
111    
112      @OneToMany(mappedBy = "measure", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
113      private List<MeasureData> measureData = new ArrayList<MeasureData>();
114    
115      @ManyToOne(fetch = FetchType.EAGER)
116      @JoinColumn(name = "characteristic_id")
117      private Characteristic characteristic;
118    
119      public Long getId() {
120        return id;
121      }
122    
123      public void setId(Long id) {
124        this.id = id;
125      }
126      
127      /**
128       * Creates a measure based on a metric and a double value
129       */
130      public MeasureModel(int metricId, Double val) {
131        if (val.isNaN() || val.isInfinite()) {
132          throw new IllegalArgumentException("Measure value is NaN. Metric=" + metricId);
133        }
134        this.metricId = metricId;
135        this.value = val;
136      }
137    
138      /**
139       * Creates a measure based on a metric and an alert level
140       */
141      public MeasureModel(int metricId, Metric.Level level) {
142        this.metricId = metricId;
143        if (level != null) {
144          this.textValue = level.toString();
145        }
146      }
147    
148      /**
149       * Creates a measure based on a metric and a string value
150       */
151      public MeasureModel(int metricId, String val) {
152        this.metricId = metricId;
153        setData(val);
154      }
155    
156      /**
157       * Creates an empty measure
158       */
159      public MeasureModel() {
160      }
161    
162      /**
163       * @return the measure double value
164       */
165      public Double getValue() {
166        return value;
167      }
168    
169      /**
170       * @return the measure description
171       */
172      public String getDescription() {
173        return description;
174      }
175    
176      /**
177       * Sets the measure description
178       */
179      public void setDescription(String description) {
180        this.description = description;
181      }
182    
183      /**
184       * Sets the measure value
185       *
186       * @throws IllegalArgumentException in case value is not a valid double
187       */
188      public MeasureModel setValue(Double value) throws IllegalArgumentException {
189        if (value != null && (value.isNaN() || value.isInfinite())) {
190          throw new IllegalArgumentException();
191        }
192        this.value = value;
193        return this;
194      }
195    
196      /**
197       * @return the measure alert level
198       */
199      public Metric.Level getLevelValue() {
200        if (textValue != null) {
201          return Metric.Level.valueOf(textValue);
202        }
203        return null;
204      }
205    
206      /**
207       * Use getData() instead
208       */
209      public String getTextValue() {
210        return textValue;
211      }
212    
213      /**
214       * Use setData() instead
215       */
216      public void setTextValue(String textValue) {
217        this.textValue = textValue;
218      }
219    
220      /**
221       * @return the measure tendency
222       */
223      public Integer getTendency() {
224        return tendency;
225      }
226    
227      /**
228       * @return whether the measure is about rule
229       */
230      public boolean isRuleMeasure() {
231        return ruleId != null || rulePriority != null;
232      }
233    
234      /**
235       * Sets the measure tendency
236       *
237       * @return the current object
238       */
239      public MeasureModel setTendency(Integer tendency) {
240        this.tendency = tendency;
241        return this;
242      }
243    
244      public Integer getMetricId() {
245        return metricId;
246      }
247    
248      public void setMetricId(Integer metricId) {
249        this.metricId = metricId;
250      }
251    
252      /**
253       * @return the snapshot id the measure is attached to
254       */
255      public Integer getSnapshotId() {
256        return snapshotId;
257      }
258    
259      /**
260       * Sets the snapshot id
261       *
262       * @return the current object
263       */
264      public MeasureModel setSnapshotId(Integer snapshotId) {
265        this.snapshotId = snapshotId;
266        return this;
267      }
268    
269      public Integer getRuleId() {
270        return ruleId;
271      }
272    
273      /**
274       * Sets the rule for the measure
275       *
276       * @return the current object
277       */
278      public MeasureModel setRuleId(Integer ruleId) {
279        this.ruleId = ruleId;
280        return this;
281      }
282    
283      /**
284       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
285       */
286      @Deprecated
287      public Integer getRulesCategoryId() {
288        return null;
289      }
290    
291      /**
292       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
293       */
294      @Deprecated
295      public MeasureModel setRulesCategoryId(Integer id) {
296        return this;
297      }
298    
299      /**
300       * @return the rule priority
301       */
302      public RulePriority getRulePriority() {
303        return rulePriority;
304      }
305    
306      /**
307       * Sets the rule priority
308       */
309      public void setRulePriority(RulePriority rulePriority) {
310        this.rulePriority = rulePriority;
311      }
312    
313      /**
314       * @return the project id
315       */
316      public Integer getProjectId() {
317        return projectId;
318      }
319    
320      /**
321       * Sets the project id
322       */
323      public void setProjectId(Integer projectId) {
324        this.projectId = projectId;
325      }
326    
327      /**
328       * @return the date of the measure
329       */
330      public Date getMeasureDate() {
331        return measureDate;
332      }
333    
334      /**
335       * Sets the date for the measure
336       *
337       * @return the current object
338       */
339      public MeasureModel setMeasureDate(Date measureDate) {
340        this.measureDate = measureDate;
341        return this;
342      }
343    
344      /**
345       * @return the alert status if there is one, null otherwise
346       */
347      public Metric.Level getAlertStatus() {
348        if (alertStatus == null) {
349          return null;
350        }
351        return Metric.Level.valueOf(alertStatus);
352      }
353    
354      /**
355       * Sets the measure alert status
356       *
357       * @return the current object
358       */
359      public MeasureModel setAlertStatus(Metric.Level level) {
360        if (level != null) {
361          this.alertStatus = level.toString();
362        } else {
363          this.alertStatus = null;
364        }
365        return this;
366      }
367    
368      /**
369       * @return the measure data
370       */
371      public String getData(Metric metric) {
372        if (this.textValue != null) {
373          return this.textValue;
374        }
375        if (metric.isDataType() && !measureData.isEmpty()) {
376          return measureData.get(0).getText();
377        }
378        return null;
379      }
380    
381      /**
382       * Sets the measure data
383       */
384      public final void setData(String data) {
385        if (data == null) {
386          this.textValue = null;
387          measureData.clear();
388    
389        } else {
390          if (data.length() > TEXT_VALUE_LENGTH) {
391            measureData.clear();
392            measureData.add(new MeasureData(this, data));
393    
394          } else {
395            this.textValue = data;
396          }
397        }
398      }
399    
400      /**
401       * Use getData() instead
402       */
403      public MeasureData getMeasureData() {
404        if (!measureData.isEmpty()) {
405          return measureData.get(0);
406        }
407        return null;
408      }
409    
410      /**
411       * Use setData() instead
412       */
413      //@Deprecated
414      public void setMeasureData(MeasureData data) {
415        measureData.clear();
416        if (data != null) {
417          this.measureData.add(data);
418        }
419      }
420    
421      /**
422       * @return the text of the alert
423       */
424      public String getAlertText() {
425        return alertText;
426      }
427    
428      /**
429       * Sets the text for the alert
430       */
431      public void setAlertText(String alertText) {
432        this.alertText = alertText;
433      }
434    
435      /**
436       * @return the measure URL
437       */
438      public String getUrl() {
439        return url;
440      }
441    
442      /**
443       * Sets the measure URL
444       */
445      public void setUrl(String url) {
446        this.url = url;
447      }
448    
449      @Override
450      public String toString() {
451        return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
452      }
453    
454      public Double getVariationValue1() {
455        return variationValue1;
456      }
457    
458      public void setVariationValue1(Double d) {
459        this.variationValue1 = d;
460      }
461    
462      public Double getVariationValue2() {
463        return variationValue2;
464      }
465    
466      public void setVariationValue2(Double d) {
467        this.variationValue2 = d;
468      }
469    
470      public Double getVariationValue3() {
471        return variationValue3;
472      }
473    
474      public void setVariationValue3(Double d) {
475        this.variationValue3 = d;
476      }
477    
478      public Double getVariationValue4() {
479        return variationValue4;
480      }
481    
482      public void setVariationValue4(Double d) {
483        this.variationValue4 = d;
484      }
485    
486      public Double getVariationValue5() {
487        return variationValue5;
488      }
489    
490      public void setVariationValue5(Double d) {
491        this.variationValue5 = d;
492      }
493    
494      /**
495       * Saves the current object to database
496       *
497       * @return the current object
498       */
499      public MeasureModel save(DatabaseSession session) {
500        MeasureData data = getMeasureData();
501        setMeasureData(null);
502        session.save(this);
503    
504        if (data != null) {
505          data.setMeasure(session.getEntity(MeasureModel.class, getId()));
506          data.setSnapshotId(snapshotId);
507          session.save(data);
508          setMeasureData(data);
509        }
510        return this;
511      }
512    
513      public Characteristic getCharacteristic() {
514        return characteristic;
515      }
516    
517      public MeasureModel setCharacteristic(Characteristic c) {
518        this.characteristic = c;
519        return this;
520      }
521    
522      @Override
523      public Object clone() {
524        MeasureModel clone = new MeasureModel();
525        clone.setMetricId(getMetricId());
526        clone.setDescription(getDescription());
527        clone.setTextValue(getTextValue());
528        clone.setAlertStatus(getAlertStatus());
529        clone.setAlertText(getAlertText());
530        clone.setTendency(getTendency());
531        clone.setVariationValue1(getVariationValue1());
532        clone.setVariationValue2(getVariationValue2());
533        clone.setVariationValue3(getVariationValue3());
534        clone.setVariationValue4(getVariationValue4());
535        clone.setVariationValue5(getVariationValue5());
536        clone.setValue(getValue());
537        clone.setRulePriority(getRulePriority());
538        clone.setRuleId(getRuleId());
539        clone.setSnapshotId(getSnapshotId());
540        clone.setMeasureDate(getMeasureDate());
541        clone.setUrl(getUrl());
542        clone.setCharacteristic(getCharacteristic());
543        return clone;
544      }
545    }