001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube 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 * SonarQube 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 License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.database.model;
021
022import com.google.common.base.Charsets;
023import com.google.common.base.Throwables;
024import org.apache.commons.lang.builder.ReflectionToStringBuilder;
025import org.apache.commons.lang.builder.ToStringStyle;
026import org.sonar.api.database.DatabaseSession;
027import org.sonar.api.measures.Metric;
028import org.sonar.api.rules.RulePriority;
029
030import javax.persistence.Column;
031import javax.persistence.Entity;
032import javax.persistence.EnumType;
033import javax.persistence.Enumerated;
034import javax.persistence.GeneratedValue;
035import javax.persistence.Id;
036import javax.persistence.Table;
037import java.io.UnsupportedEncodingException;
038
039/**
040 * This class is the Hibernate model to store a measure in the DB
041 */
042@Entity
043@Table(name = "project_measures")
044public class MeasureModel implements Cloneable {
045
046  public static final int TEXT_VALUE_LENGTH = 4000;
047
048  @Id
049  @Column(name = "id")
050  @GeneratedValue
051  private Long id;
052
053  @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20)
054  private Double value = 0.0;
055
056  @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH)
057  private String textValue;
058
059  @Column(name = "tendency", updatable = true, nullable = true)
060  private Integer tendency;
061
062  @Column(name = "metric_id", updatable = false, nullable = false)
063  private Integer metricId;
064
065  @Column(name = "snapshot_id", updatable = true, nullable = true)
066  private Integer snapshotId;
067
068  @Column(name = "project_id", updatable = true, nullable = true)
069  private Integer projectId;
070
071  @Column(name = "description", updatable = true, nullable = true, length = 4000)
072  private String description;
073
074  @Column(name = "rule_id", updatable = true, nullable = true)
075  private Integer ruleId;
076
077  @Column(name = "rule_priority", updatable = false, nullable = true)
078  @Enumerated(EnumType.ORDINAL)
079  private RulePriority rulePriority;
080
081  @Column(name = "alert_status", updatable = true, nullable = true, length = 5)
082  private String alertStatus;
083
084  @Column(name = "alert_text", updatable = true, nullable = true, length = 4000)
085  private String alertText;
086
087  @Column(name = "variation_value_1", updatable = true, nullable = true)
088  private Double variationValue1;
089
090  @Column(name = "variation_value_2", updatable = true, nullable = true)
091  private Double variationValue2;
092
093  @Column(name = "variation_value_3", updatable = true, nullable = true)
094  private Double variationValue3;
095
096  @Column(name = "variation_value_4", updatable = true, nullable = true)
097  private Double variationValue4;
098
099  @Column(name = "variation_value_5", updatable = true, nullable = true)
100  private Double variationValue5;
101
102  @Column(name = "url", updatable = true, nullable = true, length = 2000)
103  private String url;
104
105  @Column(name = "characteristic_id", nullable = true)
106  private Integer characteristicId;
107
108  @Column(name = "person_id", updatable = true, nullable = true)
109  private Integer personId;
110
111  @Column(name = "measure_data", updatable = true, nullable = true, length = 167772150)
112  private byte[] data;
113
114  /**
115   * Creates a measure based on a metric and a double value
116   */
117  public MeasureModel(int metricId, Double val) {
118    if (val.isNaN() || val.isInfinite()) {
119      throw new IllegalArgumentException("Measure value is NaN. Metric=" + metricId);
120    }
121    this.metricId = metricId;
122    this.value = val;
123  }
124
125  /**
126   * Creates a measure based on a metric and an alert level
127   */
128  public MeasureModel(int metricId, Metric.Level level) {
129    this.metricId = metricId;
130    if (level != null) {
131      this.textValue = level.toString();
132    }
133  }
134
135  /**
136   * Creates a measure based on a metric and a string value
137   */
138  public MeasureModel(int metricId, String val) {
139    this.metricId = metricId;
140    setData(val);
141  }
142
143  /**
144   * Creates an empty measure
145   */
146  public MeasureModel() {
147  }
148
149  public Long getId() {
150    return id;
151  }
152
153  public void setId(Long id) {
154    this.id = id;
155  }
156
157  /**
158   * @return the measure double value
159   */
160  public Double getValue() {
161    return value;
162  }
163
164  /**
165   * Sets the measure value
166   *
167   * @throws IllegalArgumentException in case value is not a valid double
168   */
169  public MeasureModel setValue(Double value) {
170    if (value != null && (value.isNaN() || value.isInfinite())) {
171      throw new IllegalArgumentException();
172    }
173    this.value = value;
174    return this;
175  }
176
177  /**
178   * @return the measure description
179   */
180  public String getDescription() {
181    return description;
182  }
183
184  /**
185   * Sets the measure description
186   */
187  public void setDescription(String description) {
188    this.description = description;
189  }
190
191  /**
192   * @return the measure alert level
193   */
194  public Metric.Level getLevelValue() {
195    if (textValue != null) {
196      return Metric.Level.valueOf(textValue);
197    }
198    return null;
199  }
200
201  /**
202   * Use getData() instead
203   */
204  public String getTextValue() {
205    return textValue;
206  }
207
208  /**
209   * Use setData() instead
210   */
211  public void setTextValue(String textValue) {
212    this.textValue = textValue;
213  }
214
215  /**
216   * @return the measure tendency
217   */
218  public Integer getTendency() {
219    return tendency;
220  }
221
222  /**
223   * Sets the measure tendency
224   *
225   * @return the current object
226   */
227  public MeasureModel setTendency(Integer tendency) {
228    this.tendency = tendency;
229    return this;
230  }
231
232  /**
233   * @return whether the measure is about rule
234   */
235  public boolean isRuleMeasure() {
236    return ruleId != null || rulePriority != null;
237  }
238
239  public Integer getMetricId() {
240    return metricId;
241  }
242
243  public void setMetricId(Integer metricId) {
244    this.metricId = metricId;
245  }
246
247  /**
248   * @return the snapshot id the measure is attached to
249   */
250  public Integer getSnapshotId() {
251    return snapshotId;
252  }
253
254  /**
255   * Sets the snapshot id
256   *
257   * @return the current object
258   */
259  public MeasureModel setSnapshotId(Integer snapshotId) {
260    this.snapshotId = snapshotId;
261    return this;
262  }
263
264  public Integer getRuleId() {
265    return ruleId;
266  }
267
268  /**
269   * Sets the rule for the measure
270   *
271   * @return the current object
272   */
273  public MeasureModel setRuleId(Integer ruleId) {
274    this.ruleId = ruleId;
275    return this;
276  }
277
278  /**
279   * @return the rule priority
280   */
281  public RulePriority getRulePriority() {
282    return rulePriority;
283  }
284
285  /**
286   * Sets the rule priority
287   */
288  public void setRulePriority(RulePriority rulePriority) {
289    this.rulePriority = rulePriority;
290  }
291
292  /**
293   * @return the project id
294   */
295  public Integer getProjectId() {
296    return projectId;
297  }
298
299  /**
300   * Sets the project id
301   */
302  public void setProjectId(Integer projectId) {
303    this.projectId = projectId;
304  }
305
306  /**
307   * @return the alert status if there is one, null otherwise
308   */
309  public Metric.Level getAlertStatus() {
310    if (alertStatus == null) {
311      return null;
312    }
313    return Metric.Level.valueOf(alertStatus);
314  }
315
316  /**
317   * Sets the measure alert status
318   *
319   * @return the current object
320   */
321  public MeasureModel setAlertStatus(Metric.Level level) {
322    if (level != null) {
323      this.alertStatus = level.toString();
324    } else {
325      this.alertStatus = null;
326    }
327    return this;
328  }
329
330  /**
331   * @return the measure data
332   */
333  public String getData(Metric metric) {
334    if (this.textValue != null) {
335      return this.textValue;
336    }
337    if (metric.isDataType() && data != null) {
338      try {
339        return new String(data, Charsets.UTF_8.name());
340      } catch (UnsupportedEncodingException e) {
341        // how is it possible to not support UTF-8 ?
342        Throwables.propagate(e);
343      }
344    }
345    return null;
346  }
347
348  /**
349   * Sets the measure data
350   */
351  public final void setData(String data) {
352    if (data == null) {
353      this.textValue = null;
354      this.data = null;
355
356    } else {
357      if (data.length() > TEXT_VALUE_LENGTH) {
358        this.textValue = null;
359        this.data = data.getBytes(Charsets.UTF_8);
360      } else {
361        this.textValue = data;
362        this.data = null;
363      }
364    }
365  }
366
367  /**
368   * @return the text of the alert
369   */
370  public String getAlertText() {
371    return alertText;
372  }
373
374  /**
375   * Sets the text for the alert
376   */
377  public void setAlertText(String alertText) {
378    this.alertText = alertText;
379  }
380
381  /**
382   * @return the measure URL
383   */
384  public String getUrl() {
385    return url;
386  }
387
388  /**
389   * Sets the measure URL
390   */
391  public void setUrl(String url) {
392    this.url = url;
393  }
394
395  @Override
396  public String toString() {
397    return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
398  }
399
400  public Double getVariationValue1() {
401    return variationValue1;
402  }
403
404  public void setVariationValue1(Double d) {
405    this.variationValue1 = d;
406  }
407
408  public Double getVariationValue2() {
409    return variationValue2;
410  }
411
412  public void setVariationValue2(Double d) {
413    this.variationValue2 = d;
414  }
415
416  public Double getVariationValue3() {
417    return variationValue3;
418  }
419
420  public void setVariationValue3(Double d) {
421    this.variationValue3 = d;
422  }
423
424  public Double getVariationValue4() {
425    return variationValue4;
426  }
427
428  public void setVariationValue4(Double d) {
429    this.variationValue4 = d;
430  }
431
432  public Double getVariationValue5() {
433    return variationValue5;
434  }
435
436  public void setVariationValue5(Double d) {
437    this.variationValue5 = d;
438  }
439
440  /**
441   * Saves the current object to database
442   *
443   * @return the current object
444   */
445  public MeasureModel save(DatabaseSession session) {
446    session.save(this);
447    return this;
448  }
449
450  public Integer getCharacteristicId() {
451    return characteristicId;
452  }
453
454  public MeasureModel setCharacteristicId(Integer characteristicId) {
455    this.characteristicId = characteristicId;
456    return this;
457  }
458
459  public Integer getPersonId() {
460    return personId;
461  }
462
463  public MeasureModel setPersonId(Integer i) {
464    this.personId = i;
465    return this;
466  }
467
468  @Override
469  public Object clone() {
470    MeasureModel clone = new MeasureModel();
471    clone.setMetricId(getMetricId());
472    clone.setDescription(getDescription());
473    clone.setTextValue(getTextValue());
474    clone.setAlertStatus(getAlertStatus());
475    clone.setAlertText(getAlertText());
476    clone.setTendency(getTendency());
477    clone.setVariationValue1(getVariationValue1());
478    clone.setVariationValue2(getVariationValue2());
479    clone.setVariationValue3(getVariationValue3());
480    clone.setVariationValue4(getVariationValue4());
481    clone.setVariationValue5(getVariationValue5());
482    clone.setValue(getValue());
483    clone.setRulePriority(getRulePriority());
484    clone.setRuleId(getRuleId());
485    clone.setSnapshotId(getSnapshotId());
486    clone.setUrl(getUrl());
487    clone.setCharacteristicId(getCharacteristicId());
488    clone.setPersonId(getPersonId());
489    return clone;
490  }
491
492}