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 @Column(name = "rule_priority", updatable = false, nullable = true)
086 @Enumerated(EnumType.ORDINAL)
087 private RulePriority rulePriority;
088
089 @Column(name = "alert_status", updatable = true, nullable = true, length = 5)
090 private String alertStatus;
091
092 @Column(name = "alert_text", updatable = true, nullable = true, length = 4000)
093 private String alertText;
094
095 @Column(name = "variation_value_1", updatable = true, nullable = true)
096 private Double variationValue1;
097
098 @Column(name = "variation_value_2", updatable = true, nullable = true)
099 private Double variationValue2;
100
101 @Column(name = "variation_value_3", updatable = true, nullable = true)
102 private Double variationValue3;
103
104 @Column(name = "variation_value_4", updatable = true, nullable = true)
105 private Double variationValue4;
106
107 @Column(name = "variation_value_5", updatable = true, nullable = true)
108 private Double variationValue5;
109
110 @Column(name = "url", updatable = true, nullable = true, length = 2000)
111 private String url;
112
113 @Column(name = "characteristic_id", nullable = true)
114 private Integer characteristicId;
115
116 @Column(name = "person_id", updatable = true, nullable = true)
117 private Integer personId;
118
119 @Column(name = "measure_data", updatable = true, nullable = true, length = 167772150)
120 private byte[] data;
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() && data != null) {
363 try {
364 return new String(data, Charsets.UTF_8.name());
365 } catch (UnsupportedEncodingException e) {
366 // how is it possible to not support UTF-8 ?
367 Throwables.propagate(e);
368 }
369 }
370 return null;
371 }
372
373 /**
374 * Sets the measure data
375 */
376 public final void setData(String data) {
377 if (data == null) {
378 this.textValue = null;
379 this.data = null;
380
381 } else {
382 if (data.length() > TEXT_VALUE_LENGTH) {
383 this.textValue = null;
384 this.data = data.getBytes(Charsets.UTF_8);
385 } else {
386 this.textValue = data;
387 this.data = null;
388 }
389 }
390 }
391
392 /**
393 * @return the text of the alert
394 */
395 public String getAlertText() {
396 return alertText;
397 }
398
399 /**
400 * Sets the text for the alert
401 */
402 public void setAlertText(String alertText) {
403 this.alertText = alertText;
404 }
405
406 /**
407 * @return the measure URL
408 */
409 public String getUrl() {
410 return url;
411 }
412
413 /**
414 * Sets the measure URL
415 */
416 public void setUrl(String url) {
417 this.url = url;
418 }
419
420 @Override
421 public String toString() {
422 return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
423 }
424
425 public Double getVariationValue1() {
426 return variationValue1;
427 }
428
429 public void setVariationValue1(Double d) {
430 this.variationValue1 = d;
431 }
432
433 public Double getVariationValue2() {
434 return variationValue2;
435 }
436
437 public void setVariationValue2(Double d) {
438 this.variationValue2 = d;
439 }
440
441 public Double getVariationValue3() {
442 return variationValue3;
443 }
444
445 public void setVariationValue3(Double d) {
446 this.variationValue3 = d;
447 }
448
449 public Double getVariationValue4() {
450 return variationValue4;
451 }
452
453 public void setVariationValue4(Double d) {
454 this.variationValue4 = d;
455 }
456
457 public Double getVariationValue5() {
458 return variationValue5;
459 }
460
461 public void setVariationValue5(Double d) {
462 this.variationValue5 = d;
463 }
464
465 /**
466 * Saves the current object to database
467 *
468 * @return the current object
469 */
470 public MeasureModel save(DatabaseSession session) {
471 session.save(this);
472 return this;
473 }
474
475 public Integer getCharacteristicId() {
476 return characteristicId;
477 }
478
479 public MeasureModel setCharacteristicId(Integer characteristicId) {
480 this.characteristicId = characteristicId;
481 return this;
482 }
483
484 public Integer getPersonId() {
485 return personId;
486 }
487
488 public MeasureModel setPersonId(Integer i) {
489 this.personId = i;
490 return this;
491 }
492
493 @Override
494 public Object clone() {
495 MeasureModel clone = new MeasureModel();
496 clone.setMetricId(getMetricId());
497 clone.setDescription(getDescription());
498 clone.setTextValue(getTextValue());
499 clone.setAlertStatus(getAlertStatus());
500 clone.setAlertText(getAlertText());
501 clone.setTendency(getTendency());
502 clone.setVariationValue1(getVariationValue1());
503 clone.setVariationValue2(getVariationValue2());
504 clone.setVariationValue3(getVariationValue3());
505 clone.setVariationValue4(getVariationValue4());
506 clone.setVariationValue5(getVariationValue5());
507 clone.setValue(getValue());
508 clone.setRulePriority(getRulePriority());
509 clone.setRuleId(getRuleId());
510 clone.setSnapshotId(getSnapshotId());
511 clone.setMeasureDate(getMeasureDate());
512 clone.setUrl(getUrl());
513 clone.setCharacteristicId(getCharacteristicId());
514 clone.setPersonId(getPersonId());
515 return clone;
516 }
517
518 }