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