001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 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    
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;//NOSONAR this field is kept for backward-compatiblity of API
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      @Column(name = "person_id", updatable = true, nullable = true)
120      private Integer personId;
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       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
288       */
289      @Deprecated
290      public Integer getRulesCategoryId() {
291        return null;
292      }
293    
294      /**
295       * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
296       */
297      @Deprecated
298      public MeasureModel setRulesCategoryId(Integer id) {
299        return this;
300      }
301    
302      /**
303       * @return the rule priority
304       */
305      public RulePriority getRulePriority() {
306        return rulePriority;
307      }
308    
309      /**
310       * Sets the rule priority
311       */
312      public void setRulePriority(RulePriority rulePriority) {
313        this.rulePriority = rulePriority;
314      }
315    
316      /**
317       * @return the project id
318       */
319      public Integer getProjectId() {
320        return projectId;
321      }
322    
323      /**
324       * Sets the project id
325       */
326      public void setProjectId(Integer projectId) {
327        this.projectId = projectId;
328      }
329    
330      /**
331       * @return the date of the measure
332       */
333      public Date getMeasureDate() {
334        return measureDate;
335      }
336    
337      /**
338       * Sets the date for the measure
339       *
340       * @return the current object
341       */
342      public MeasureModel setMeasureDate(Date measureDate) {
343        this.measureDate = measureDate;
344        return this;
345      }
346    
347      /**
348       * @return the alert status if there is one, null otherwise
349       */
350      public Metric.Level getAlertStatus() {
351        if (alertStatus == null) {
352          return null;
353        }
354        return Metric.Level.valueOf(alertStatus);
355      }
356    
357      /**
358       * Sets the measure alert status
359       *
360       * @return the current object
361       */
362      public MeasureModel setAlertStatus(Metric.Level level) {
363        if (level != null) {
364          this.alertStatus = level.toString();
365        } else {
366          this.alertStatus = null;
367        }
368        return this;
369      }
370    
371      /**
372       * @return the measure data
373       */
374      public String getData(Metric metric) {
375        if (this.textValue != null) {
376          return this.textValue;
377        }
378        if (metric.isDataType() && !measureData.isEmpty()) {
379          return measureData.get(0).getText();
380        }
381        return null;
382      }
383    
384      /**
385       * Sets the measure data
386       */
387      public final void setData(String data) {
388        if (data == null) {
389          this.textValue = null;
390          measureData.clear();
391    
392        } else {
393          if (data.length() > TEXT_VALUE_LENGTH) {
394            measureData.clear();
395            measureData.add(new MeasureData(this, data));
396    
397          } else {
398            this.textValue = data;
399          }
400        }
401      }
402    
403      /**
404       * Use getData() instead
405       */
406      public MeasureData getMeasureData() {
407        if (!measureData.isEmpty()) {
408          return measureData.get(0);
409        }
410        return null;
411      }
412    
413      /**
414       * Use setData() instead
415       */
416      //@Deprecated
417      public void setMeasureData(MeasureData data) {
418        measureData.clear();
419        if (data != null) {
420          this.measureData.add(data);
421        }
422      }
423    
424      /**
425       * @return the text of the alert
426       */
427      public String getAlertText() {
428        return alertText;
429      }
430    
431      /**
432       * Sets the text for the alert
433       */
434      public void setAlertText(String alertText) {
435        this.alertText = alertText;
436      }
437    
438      /**
439       * @return the measure URL
440       */
441      public String getUrl() {
442        return url;
443      }
444    
445      /**
446       * Sets the measure URL
447       */
448      public void setUrl(String url) {
449        this.url = url;
450      }
451    
452      @Override
453      public String toString() {
454        return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
455      }
456    
457      public Double getVariationValue1() {
458        return variationValue1;
459      }
460    
461      public void setVariationValue1(Double d) {
462        this.variationValue1 = d;
463      }
464    
465      public Double getVariationValue2() {
466        return variationValue2;
467      }
468    
469      public void setVariationValue2(Double d) {
470        this.variationValue2 = d;
471      }
472    
473      public Double getVariationValue3() {
474        return variationValue3;
475      }
476    
477      public void setVariationValue3(Double d) {
478        this.variationValue3 = d;
479      }
480    
481      public Double getVariationValue4() {
482        return variationValue4;
483      }
484    
485      public void setVariationValue4(Double d) {
486        this.variationValue4 = d;
487      }
488    
489      public Double getVariationValue5() {
490        return variationValue5;
491      }
492    
493      public void setVariationValue5(Double d) {
494        this.variationValue5 = d;
495      }
496    
497      /**
498       * Saves the current object to database
499       *
500       * @return the current object
501       */
502      public MeasureModel save(DatabaseSession session) {
503        MeasureData data = getMeasureData();
504        setMeasureData(null);
505        session.save(this);
506    
507        if (data != null) {
508          data.setMeasure(session.getEntity(MeasureModel.class, getId()));
509          data.setSnapshotId(snapshotId);
510          session.save(data);
511          setMeasureData(data);
512        }
513        return this;
514      }
515    
516      public Characteristic getCharacteristic() {
517        return characteristic;
518      }
519    
520      public MeasureModel setCharacteristic(Characteristic c) {
521        this.characteristic = c;
522        return this;
523      }
524    
525      public Integer getPersonId() {
526        return personId;
527      }
528    
529      public MeasureModel setPersonId(Integer i) {
530        this.personId = i;
531        return this;
532      }
533    
534      @Override
535      public Object clone() {
536        MeasureModel clone = new MeasureModel();
537        clone.setMetricId(getMetricId());
538        clone.setDescription(getDescription());
539        clone.setTextValue(getTextValue());
540        clone.setAlertStatus(getAlertStatus());
541        clone.setAlertText(getAlertText());
542        clone.setTendency(getTendency());
543        clone.setVariationValue1(getVariationValue1());
544        clone.setVariationValue2(getVariationValue2());
545        clone.setVariationValue3(getVariationValue3());
546        clone.setVariationValue4(getVariationValue4());
547        clone.setVariationValue5(getVariationValue5());
548        clone.setValue(getValue());
549        clone.setRulePriority(getRulePriority());
550        clone.setRuleId(getRuleId());
551        clone.setSnapshotId(getSnapshotId());
552        clone.setMeasureDate(getMeasureDate());
553        clone.setUrl(getUrl());
554        clone.setCharacteristic(getCharacteristic());
555        clone.setPersonId(getPersonId());
556        return clone;
557      }
558    
559    }