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 com.google.common.base.Charsets;
023 import com.google.common.base.Throwables;
024 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
025 import org.apache.commons.lang.builder.ToStringStyle;
026 import org.sonar.api.database.DatabaseSession;
027 import org.sonar.api.measures.Metric;
028 import org.sonar.api.rules.RulePriority;
029
030 import javax.persistence.Column;
031 import javax.persistence.Entity;
032 import javax.persistence.EnumType;
033 import javax.persistence.Enumerated;
034 import javax.persistence.GeneratedValue;
035 import javax.persistence.Id;
036 import javax.persistence.Table;
037 import javax.persistence.Temporal;
038 import javax.persistence.TemporalType;
039
040 import java.io.UnsupportedEncodingException;
041 import java.util.Date;
042
043 /**
044 * This class is the Hibernate model to store a measure in the DB
045 */
046 @Entity
047 @Table(name = "project_measures")
048 public class MeasureModel implements Cloneable {
049
050 public static final int TEXT_VALUE_LENGTH = 4000;
051
052 @Id
053 @Column(name = "id")
054 @GeneratedValue
055 private Long id;
056
057 @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20)
058 private Double value = 0.0;
059
060 @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH)
061 private String textValue;
062
063 @Column(name = "tendency", updatable = true, nullable = true)
064 private Integer tendency;
065
066 @Column(name = "metric_id", updatable = false, nullable = false)
067 private Integer metricId;
068
069 @Column(name = "snapshot_id", updatable = true, nullable = true)
070 private Integer snapshotId;
071
072 @Column(name = "project_id", updatable = true, nullable = true)
073 private Integer projectId;
074
075 @Column(name = "description", updatable = true, nullable = true, length = 4000)
076 private String description;
077
078 @Temporal(TemporalType.TIMESTAMP)
079 @Column(name = "measure_date", updatable = true, nullable = true)
080 private Date measureDate;
081
082 @Column(name = "rule_id", updatable = true, nullable = true)
083 private Integer ruleId;
084
085 /**
086 * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007
087 */
088 @Deprecated
089 @Column(name = "rules_category_id", nullable = true)
090 private Integer rulesCategoryId;// NOSONAR this field is kept for backward-compatiblity of API
091
092 @Column(name = "rule_priority", updatable = false, nullable = true)
093 @Enumerated(EnumType.ORDINAL)
094 private RulePriority rulePriority;
095
096 @Column(name = "alert_status", updatable = true, nullable = true, length = 5)
097 private String alertStatus;
098
099 @Column(name = "alert_text", updatable = true, nullable = true, length = 4000)
100 private String alertText;
101
102 @Column(name = "variation_value_1", updatable = true, nullable = true)
103 private Double variationValue1;
104
105 @Column(name = "variation_value_2", updatable = true, nullable = true)
106 private Double variationValue2;
107
108 @Column(name = "variation_value_3", updatable = true, nullable = true)
109 private Double variationValue3;
110
111 @Column(name = "variation_value_4", updatable = true, nullable = true)
112 private Double variationValue4;
113
114 @Column(name = "variation_value_5", updatable = true, nullable = true)
115 private Double variationValue5;
116
117 @Column(name = "url", updatable = true, nullable = true, length = 2000)
118 private String url;
119
120 @Column(name = "characteristic_id", nullable = true)
121 private Integer characteristicId;
122
123 @Column(name = "person_id", updatable = true, nullable = true)
124 private Integer personId;
125
126 @Column(name = "measure_data", updatable = true, nullable = true, length = 167772150)
127 private byte[] data;
128
129 public Long getId() {
130 return id;
131 }
132
133 public void setId(Long id) {
134 this.id = id;
135 }
136
137 /**
138 * Creates a measure based on a metric and a double value
139 */
140 public MeasureModel(int metricId, Double val) {
141 if (val.isNaN() || val.isInfinite()) {
142 throw new IllegalArgumentException("Measure value is NaN. Metric=" + metricId);
143 }
144 this.metricId = metricId;
145 this.value = val;
146 }
147
148 /**
149 * Creates a measure based on a metric and an alert level
150 */
151 public MeasureModel(int metricId, Metric.Level level) {
152 this.metricId = metricId;
153 if (level != null) {
154 this.textValue = level.toString();
155 }
156 }
157
158 /**
159 * Creates a measure based on a metric and a string value
160 */
161 public MeasureModel(int metricId, String val) {
162 this.metricId = metricId;
163 setData(val);
164 }
165
166 /**
167 * Creates an empty measure
168 */
169 public MeasureModel() {
170 }
171
172 /**
173 * @return the measure double value
174 */
175 public Double getValue() {
176 return value;
177 }
178
179 /**
180 * @return the measure description
181 */
182 public String getDescription() {
183 return description;
184 }
185
186 /**
187 * Sets the measure description
188 */
189 public void setDescription(String description) {
190 this.description = description;
191 }
192
193 /**
194 * Sets the measure value
195 *
196 * @throws IllegalArgumentException in case value is not a valid double
197 */
198 public MeasureModel setValue(Double value) {
199 if (value != null && (value.isNaN() || value.isInfinite())) {
200 throw new IllegalArgumentException();
201 }
202 this.value = value;
203 return this;
204 }
205
206 /**
207 * @return the measure alert level
208 */
209 public Metric.Level getLevelValue() {
210 if (textValue != null) {
211 return Metric.Level.valueOf(textValue);
212 }
213 return null;
214 }
215
216 /**
217 * Use getData() instead
218 */
219 public String getTextValue() {
220 return textValue;
221 }
222
223 /**
224 * Use setData() instead
225 */
226 public void setTextValue(String textValue) {
227 this.textValue = textValue;
228 }
229
230 /**
231 * @return the measure tendency
232 */
233 public Integer getTendency() {
234 return tendency;
235 }
236
237 /**
238 * @return whether the measure is about rule
239 */
240 public boolean isRuleMeasure() {
241 return ruleId != null || rulePriority != null;
242 }
243
244 /**
245 * Sets the measure tendency
246 *
247 * @return the current object
248 */
249 public MeasureModel setTendency(Integer tendency) {
250 this.tendency = tendency;
251 return this;
252 }
253
254 public Integer getMetricId() {
255 return metricId;
256 }
257
258 public void setMetricId(Integer metricId) {
259 this.metricId = metricId;
260 }
261
262 /**
263 * @return the snapshot id the measure is attached to
264 */
265 public Integer getSnapshotId() {
266 return snapshotId;
267 }
268
269 /**
270 * Sets the snapshot id
271 *
272 * @return the current object
273 */
274 public MeasureModel setSnapshotId(Integer snapshotId) {
275 this.snapshotId = snapshotId;
276 return this;
277 }
278
279 public Integer getRuleId() {
280 return ruleId;
281 }
282
283 /**
284 * Sets the rule for the measure
285 *
286 * @return the current object
287 */
288 public MeasureModel setRuleId(Integer ruleId) {
289 this.ruleId = ruleId;
290 return this;
291 }
292
293 /**
294 * @return the rule priority
295 */
296 public RulePriority getRulePriority() {
297 return rulePriority;
298 }
299
300 /**
301 * Sets the rule priority
302 */
303 public void setRulePriority(RulePriority rulePriority) {
304 this.rulePriority = rulePriority;
305 }
306
307 /**
308 * @return the project id
309 */
310 public Integer getProjectId() {
311 return projectId;
312 }
313
314 /**
315 * Sets the project id
316 */
317 public void setProjectId(Integer projectId) {
318 this.projectId = projectId;
319 }
320
321 /**
322 * @return the date of the measure
323 */
324 public Date getMeasureDate() {
325 return measureDate;
326 }
327
328 /**
329 * Sets the date for the measure
330 *
331 * @return the current object
332 */
333 public MeasureModel setMeasureDate(Date measureDate) {
334 this.measureDate = measureDate;
335 return this;
336 }
337
338 /**
339 * @return the alert status if there is one, null otherwise
340 */
341 public Metric.Level getAlertStatus() {
342 if (alertStatus == null) {
343 return null;
344 }
345 return Metric.Level.valueOf(alertStatus);
346 }
347
348 /**
349 * Sets the measure alert status
350 *
351 * @return the current object
352 */
353 public MeasureModel setAlertStatus(Metric.Level level) {
354 if (level != null) {
355 this.alertStatus = level.toString();
356 } else {
357 this.alertStatus = null;
358 }
359 return this;
360 }
361
362 /**
363 * @return the measure data
364 */
365 public String getData(Metric metric) {
366 if (this.textValue != null) {
367 return this.textValue;
368 }
369 if (metric.isDataType() && data != null) {
370 try {
371 return new String(data, Charsets.UTF_8.name());
372 } catch (UnsupportedEncodingException e) {
373 // how is it possible to not support UTF-8 ?
374 Throwables.propagate(e);
375 }
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 this.data = null;
387
388 } else {
389 if (data.length() > TEXT_VALUE_LENGTH) {
390 this.textValue = null;
391 this.data = data.getBytes(Charsets.UTF_8);
392 } else {
393 this.textValue = data;
394 this.data = null;
395 }
396 }
397 }
398
399 /**
400 * @return the text of the alert
401 */
402 public String getAlertText() {
403 return alertText;
404 }
405
406 /**
407 * Sets the text for the alert
408 */
409 public void setAlertText(String alertText) {
410 this.alertText = alertText;
411 }
412
413 /**
414 * @return the measure URL
415 */
416 public String getUrl() {
417 return url;
418 }
419
420 /**
421 * Sets the measure URL
422 */
423 public void setUrl(String url) {
424 this.url = url;
425 }
426
427 @Override
428 public String toString() {
429 return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
430 }
431
432 public Double getVariationValue1() {
433 return variationValue1;
434 }
435
436 public void setVariationValue1(Double d) {
437 this.variationValue1 = d;
438 }
439
440 public Double getVariationValue2() {
441 return variationValue2;
442 }
443
444 public void setVariationValue2(Double d) {
445 this.variationValue2 = d;
446 }
447
448 public Double getVariationValue3() {
449 return variationValue3;
450 }
451
452 public void setVariationValue3(Double d) {
453 this.variationValue3 = d;
454 }
455
456 public Double getVariationValue4() {
457 return variationValue4;
458 }
459
460 public void setVariationValue4(Double d) {
461 this.variationValue4 = d;
462 }
463
464 public Double getVariationValue5() {
465 return variationValue5;
466 }
467
468 public void setVariationValue5(Double d) {
469 this.variationValue5 = d;
470 }
471
472 /**
473 * Saves the current object to database
474 *
475 * @return the current object
476 */
477 public MeasureModel save(DatabaseSession session) {
478 session.save(this);
479 return this;
480 }
481
482 public Integer getCharacteristicId() {
483 return characteristicId;
484 }
485
486 public MeasureModel setCharacteristicId(Integer characteristicId) {
487 this.characteristicId = characteristicId;
488 return this;
489 }
490
491 public Integer getPersonId() {
492 return personId;
493 }
494
495 public MeasureModel setPersonId(Integer i) {
496 this.personId = i;
497 return this;
498 }
499
500 @Override
501 public Object clone() {
502 MeasureModel clone = new MeasureModel();
503 clone.setMetricId(getMetricId());
504 clone.setDescription(getDescription());
505 clone.setTextValue(getTextValue());
506 clone.setAlertStatus(getAlertStatus());
507 clone.setAlertText(getAlertText());
508 clone.setTendency(getTendency());
509 clone.setVariationValue1(getVariationValue1());
510 clone.setVariationValue2(getVariationValue2());
511 clone.setVariationValue3(getVariationValue3());
512 clone.setVariationValue4(getVariationValue4());
513 clone.setVariationValue5(getVariationValue5());
514 clone.setValue(getValue());
515 clone.setRulePriority(getRulePriority());
516 clone.setRuleId(getRuleId());
517 clone.setSnapshotId(getSnapshotId());
518 clone.setMeasureDate(getMeasureDate());
519 clone.setUrl(getUrl());
520 clone.setCharacteristicId(getCharacteristicId());
521 clone.setPersonId(getPersonId());
522 return clone;
523 }
524
525 }