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