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 }