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