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