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 }