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 * @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() && !measureData.isEmpty()) {
363 return measureData.get(0).getText();
364 }
365 return null;
366 }
367
368 /**
369 * Sets the measure data
370 */
371 public final void setData(String data) {
372 if (data == null) {
373 this.textValue = null;
374 measureData.clear();
375
376 } else {
377 if (data.length() > TEXT_VALUE_LENGTH) {
378 measureData.clear();
379 measureData.add(new MeasureData(this, data));
380
381 } else {
382 this.textValue = data;
383 }
384 }
385 }
386
387 /**
388 * Use getData() instead
389 */
390 public MeasureData getMeasureData() {
391 if (!measureData.isEmpty()) {
392 return measureData.get(0);
393 }
394 return null;
395 }
396
397 /**
398 * Use setData() instead
399 */
400 //@Deprecated
401 public void setMeasureData(MeasureData data) {
402 measureData.clear();
403 if (data != null) {
404 this.measureData.add(data);
405 }
406 }
407
408 /**
409 * @return the text of the alert
410 */
411 public String getAlertText() {
412 return alertText;
413 }
414
415 /**
416 * Sets the text for the alert
417 */
418 public void setAlertText(String alertText) {
419 this.alertText = alertText;
420 }
421
422 /**
423 * @return the measure URL
424 */
425 public String getUrl() {
426 return url;
427 }
428
429 /**
430 * Sets the measure URL
431 */
432 public void setUrl(String url) {
433 this.url = url;
434 }
435
436 @Override
437 public String toString() {
438 return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
439 }
440
441 public Double getVariationValue1() {
442 return variationValue1;
443 }
444
445 public void setVariationValue1(Double d) {
446 this.variationValue1 = d;
447 }
448
449 public Double getVariationValue2() {
450 return variationValue2;
451 }
452
453 public void setVariationValue2(Double d) {
454 this.variationValue2 = d;
455 }
456
457 public Double getVariationValue3() {
458 return variationValue3;
459 }
460
461 public void setVariationValue3(Double d) {
462 this.variationValue3 = d;
463 }
464
465 public Double getVariationValue4() {
466 return variationValue4;
467 }
468
469 public void setVariationValue4(Double d) {
470 this.variationValue4 = d;
471 }
472
473 public Double getVariationValue5() {
474 return variationValue5;
475 }
476
477 public void setVariationValue5(Double d) {
478 this.variationValue5 = d;
479 }
480
481 /**
482 * Saves the current object to database
483 *
484 * @return the current object
485 */
486 public MeasureModel save(DatabaseSession session) {
487 MeasureData data = getMeasureData();
488 setMeasureData(null);
489 session.save(this);
490
491 if (data != null) {
492 data.setMeasure(session.getEntity(MeasureModel.class, getId()));
493 data.setSnapshotId(snapshotId);
494 session.save(data);
495 setMeasureData(data);
496 }
497 return this;
498 }
499
500 public Characteristic getCharacteristic() {
501 return characteristic;
502 }
503
504 public MeasureModel setCharacteristic(Characteristic c) {
505 this.characteristic = c;
506 return this;
507 }
508
509 public Integer getPersonId() {
510 return personId;
511 }
512
513 public MeasureModel setPersonId(Integer i) {
514 this.personId = i;
515 return this;
516 }
517
518 @Override
519 public Object clone() {
520 MeasureModel clone = new MeasureModel();
521 clone.setMetricId(getMetricId());
522 clone.setDescription(getDescription());
523 clone.setTextValue(getTextValue());
524 clone.setAlertStatus(getAlertStatus());
525 clone.setAlertText(getAlertText());
526 clone.setTendency(getTendency());
527 clone.setVariationValue1(getVariationValue1());
528 clone.setVariationValue2(getVariationValue2());
529 clone.setVariationValue3(getVariationValue3());
530 clone.setVariationValue4(getVariationValue4());
531 clone.setVariationValue5(getVariationValue5());
532 clone.setValue(getValue());
533 clone.setRulePriority(getRulePriority());
534 clone.setRuleId(getRuleId());
535 clone.setSnapshotId(getSnapshotId());
536 clone.setMeasureDate(getMeasureDate());
537 clone.setUrl(getUrl());
538 clone.setCharacteristic(getCharacteristic());
539 clone.setPersonId(getPersonId());
540 return clone;
541 }
542
543 }