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 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.rules.RulePriority;
027    
028    import javax.persistence.*;
029    
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      @Column(name = "characteristic_id", nullable = true)
115      private Integer characteristicId;
116    
117      @Column(name = "person_id", updatable = true, nullable = true)
118      private Integer personId;
119    
120      public Long getId() {
121        return id;
122      }
123    
124      public void setId(Long id) {
125        this.id = id;
126      }
127    
128      /**
129       * Creates a measure based on a metric and a double value
130       */
131      public MeasureModel(int metricId, Double val) {
132        if (val.isNaN() || val.isInfinite()) {
133          throw new IllegalArgumentException("Measure value is NaN. Metric=" + metricId);
134        }
135        this.metricId = metricId;
136        this.value = val;
137      }
138    
139      /**
140       * Creates a measure based on a metric and an alert level
141       */
142      public MeasureModel(int metricId, Metric.Level level) {
143        this.metricId = metricId;
144        if (level != null) {
145          this.textValue = level.toString();
146        }
147      }
148    
149      /**
150       * Creates a measure based on a metric and a string value
151       */
152      public MeasureModel(int metricId, String val) {
153        this.metricId = metricId;
154        setData(val);
155      }
156    
157      /**
158       * Creates an empty measure
159       */
160      public MeasureModel() {
161      }
162    
163      /**
164       * @return the measure double value
165       */
166      public Double getValue() {
167        return value;
168      }
169    
170      /**
171       * @return the measure description
172       */
173      public String getDescription() {
174        return description;
175      }
176    
177      /**
178       * Sets the measure description
179       */
180      public void setDescription(String description) {
181        this.description = description;
182      }
183    
184      /**
185       * Sets the measure value
186       *
187       * @throws IllegalArgumentException in case value is not a valid double
188       */
189      public MeasureModel setValue(Double value) {
190        if (value != null && (value.isNaN() || value.isInfinite())) {
191          throw new IllegalArgumentException();
192        }
193        this.value = value;
194        return this;
195      }
196    
197      /**
198       * @return the measure alert level
199       */
200      public Metric.Level getLevelValue() {
201        if (textValue != null) {
202          return Metric.Level.valueOf(textValue);
203        }
204        return null;
205      }
206    
207      /**
208       * Use getData() instead
209       */
210      public String getTextValue() {
211        return textValue;
212      }
213    
214      /**
215       * Use setData() instead
216       */
217      public void setTextValue(String textValue) {
218        this.textValue = textValue;
219      }
220    
221      /**
222       * @return the measure tendency
223       */
224      public Integer getTendency() {
225        return tendency;
226      }
227    
228      /**
229       * @return whether the measure is about rule
230       */
231      public boolean isRuleMeasure() {
232        return ruleId != null || rulePriority != null;
233      }
234    
235      /**
236       * Sets the measure tendency
237       *
238       * @return the current object
239       */
240      public MeasureModel setTendency(Integer tendency) {
241        this.tendency = tendency;
242        return this;
243      }
244    
245      public Integer getMetricId() {
246        return metricId;
247      }
248    
249      public void setMetricId(Integer metricId) {
250        this.metricId = metricId;
251      }
252    
253      /**
254       * @return the snapshot id the measure is attached to
255       */
256      public Integer getSnapshotId() {
257        return snapshotId;
258      }
259    
260      /**
261       * Sets the snapshot id
262       *
263       * @return the current object
264       */
265      public MeasureModel setSnapshotId(Integer snapshotId) {
266        this.snapshotId = snapshotId;
267        return this;
268      }
269    
270      public Integer getRuleId() {
271        return ruleId;
272      }
273    
274      /**
275       * Sets the rule for the measure
276       *
277       * @return the current object
278       */
279      public MeasureModel setRuleId(Integer ruleId) {
280        this.ruleId = ruleId;
281        return this;
282      }
283    
284      /**
285       * @return the rule priority
286       */
287      public RulePriority getRulePriority() {
288        return rulePriority;
289      }
290    
291      /**
292       * Sets the rule priority
293       */
294      public void setRulePriority(RulePriority rulePriority) {
295        this.rulePriority = rulePriority;
296      }
297    
298      /**
299       * @return the project id
300       */
301      public Integer getProjectId() {
302        return projectId;
303      }
304    
305      /**
306       * Sets the project id
307       */
308      public void setProjectId(Integer projectId) {
309        this.projectId = projectId;
310      }
311    
312      /**
313       * @return the date of the measure
314       */
315      public Date getMeasureDate() {
316        return measureDate;
317      }
318    
319      /**
320       * Sets the date for the measure
321       *
322       * @return the current object
323       */
324      public MeasureModel setMeasureDate(Date measureDate) {
325        this.measureDate = measureDate;
326        return this;
327      }
328    
329      /**
330       * @return the alert status if there is one, null otherwise
331       */
332      public Metric.Level getAlertStatus() {
333        if (alertStatus == null) {
334          return null;
335        }
336        return Metric.Level.valueOf(alertStatus);
337      }
338    
339      /**
340       * Sets the measure alert status
341       *
342       * @return the current object
343       */
344      public MeasureModel setAlertStatus(Metric.Level level) {
345        if (level != null) {
346          this.alertStatus = level.toString();
347        } else {
348          this.alertStatus = null;
349        }
350        return this;
351      }
352    
353      /**
354       * @return the measure data
355       */
356      public String getData(Metric metric) {
357        if (this.textValue != null) {
358          return this.textValue;
359        }
360        if (metric.isDataType() && !measureData.isEmpty()) {
361          return measureData.get(0).getText();
362        }
363        return null;
364      }
365    
366      /**
367       * Sets the measure data
368       */
369      public final void setData(String data) {
370        if (data == null) {
371          this.textValue = null;
372          measureData.clear();
373    
374        } else {
375          if (data.length() > TEXT_VALUE_LENGTH) {
376            measureData.clear();
377            measureData.add(new MeasureData(this, data));
378    
379          } else {
380            this.textValue = data;
381          }
382        }
383      }
384    
385      /**
386       * Use getData() instead
387       */
388      public MeasureData getMeasureData() {
389        if (!measureData.isEmpty()) {
390          return measureData.get(0);
391        }
392        return null;
393      }
394    
395      /**
396       * Use setData() instead
397       */
398      //@Deprecated
399      public void setMeasureData(MeasureData data) {
400        measureData.clear();
401        if (data != null) {
402          this.measureData.add(data);
403        }
404      }
405    
406      /**
407       * @return the text of the alert
408       */
409      public String getAlertText() {
410        return alertText;
411      }
412    
413      /**
414       * Sets the text for the alert
415       */
416      public void setAlertText(String alertText) {
417        this.alertText = alertText;
418      }
419    
420      /**
421       * @return the measure URL
422       */
423      public String getUrl() {
424        return url;
425      }
426    
427      /**
428       * Sets the measure URL
429       */
430      public void setUrl(String url) {
431        this.url = url;
432      }
433    
434      @Override
435      public String toString() {
436        return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
437      }
438    
439      public Double getVariationValue1() {
440        return variationValue1;
441      }
442    
443      public void setVariationValue1(Double d) {
444        this.variationValue1 = d;
445      }
446    
447      public Double getVariationValue2() {
448        return variationValue2;
449      }
450    
451      public void setVariationValue2(Double d) {
452        this.variationValue2 = d;
453      }
454    
455      public Double getVariationValue3() {
456        return variationValue3;
457      }
458    
459      public void setVariationValue3(Double d) {
460        this.variationValue3 = d;
461      }
462    
463      public Double getVariationValue4() {
464        return variationValue4;
465      }
466    
467      public void setVariationValue4(Double d) {
468        this.variationValue4 = d;
469      }
470    
471      public Double getVariationValue5() {
472        return variationValue5;
473      }
474    
475      public void setVariationValue5(Double d) {
476        this.variationValue5 = d;
477      }
478    
479      /**
480       * Saves the current object to database
481       *
482       * @return the current object
483       */
484      public MeasureModel save(DatabaseSession session) {
485        MeasureData data = getMeasureData();
486        setMeasureData(null);
487        session.save(this);
488    
489        if (data != null) {
490          data.setMeasure(session.getEntity(MeasureModel.class, getId()));
491          data.setSnapshotId(snapshotId);
492          session.save(data);
493          setMeasureData(data);
494        }
495        return this;
496      }
497    
498      public Integer getCharacteristicId() {
499        return characteristicId;
500      }
501    
502      public MeasureModel setCharacteristicId(Integer characteristicId) {
503        this.characteristicId = characteristicId;
504        return this;
505      }
506    
507      public Integer getPersonId() {
508        return personId;
509      }
510    
511      public MeasureModel setPersonId(Integer i) {
512        this.personId = i;
513        return this;
514      }
515    
516      @Override
517      public Object clone() {
518        MeasureModel clone = new MeasureModel();
519        clone.setMetricId(getMetricId());
520        clone.setDescription(getDescription());
521        clone.setTextValue(getTextValue());
522        clone.setAlertStatus(getAlertStatus());
523        clone.setAlertText(getAlertText());
524        clone.setTendency(getTendency());
525        clone.setVariationValue1(getVariationValue1());
526        clone.setVariationValue2(getVariationValue2());
527        clone.setVariationValue3(getVariationValue3());
528        clone.setVariationValue4(getVariationValue4());
529        clone.setVariationValue5(getVariationValue5());
530        clone.setValue(getValue());
531        clone.setRulePriority(getRulePriority());
532        clone.setRuleId(getRuleId());
533        clone.setSnapshotId(getSnapshotId());
534        clone.setMeasureDate(getMeasureDate());
535        clone.setUrl(getUrl());
536        clone.setCharacteristicId(getCharacteristicId());
537        clone.setPersonId(getPersonId());
538        return clone;
539      }
540    
541    }