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