001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar 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 * Sonar 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 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.api.database.model; 021 022 import org.apache.commons.lang.builder.ReflectionToStringBuilder; 023 import org.apache.commons.lang.builder.ToStringStyle; 024 import org.sonar.api.database.DatabaseSession; 025 import org.sonar.api.measures.Metric; 026 import org.sonar.api.qualitymodel.Characteristic; 027 import org.sonar.api.rules.RulePriority; 028 029 import javax.persistence.*; 030 031 import java.util.ArrayList; 032 import java.util.Date; 033 import java.util.List; 034 035 /** 036 * This class is the Hibernate model to store a measure in the DB 037 */ 038 @Entity 039 @Table(name = "project_measures") 040 public class MeasureModel implements Cloneable { 041 042 public static final int TEXT_VALUE_LENGTH = 96; 043 044 @Id 045 @Column(name = "id") 046 @GeneratedValue 047 private Long id; 048 049 @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20) 050 private Double value = 0.0; 051 052 @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH) 053 private String textValue; 054 055 @Column(name = "tendency", updatable = true, nullable = true) 056 private Integer tendency; 057 058 @Column(name = "metric_id", updatable = false, nullable = false) 059 private Integer metricId; 060 061 @Column(name = "snapshot_id", updatable = true, nullable = true) 062 private Integer snapshotId; 063 064 @Column(name = "project_id", updatable = true, nullable = true) 065 private Integer projectId; 066 067 @Column(name = "description", updatable = true, nullable = true, length = 4000) 068 private String description; 069 070 @Temporal(TemporalType.TIMESTAMP) 071 @Column(name = "measure_date", updatable = true, nullable = true) 072 private Date measureDate; 073 074 @Column(name = "rule_id", updatable = true, nullable = true) 075 private Integer ruleId; 076 077 /** 078 * @deprecated since 2.5 See http://jira.codehaus.org/browse/SONAR-2007 079 */ 080 @Deprecated 081 @Column(name = "rules_category_id", nullable = true) 082 private Integer rulesCategoryId;//NOSONAR this field is kept for backward-compatiblity of API 083 084 @Column(name = "rule_priority", updatable = false, nullable = true) 085 @Enumerated(EnumType.ORDINAL) 086 private RulePriority rulePriority; 087 088 @Column(name = "alert_status", updatable = true, nullable = true, length = 5) 089 private String alertStatus; 090 091 @Column(name = "alert_text", updatable = true, nullable = true, length = 4000) 092 private String alertText; 093 094 @Column(name = "variation_value_1", updatable = true, nullable = true) 095 private Double variationValue1; 096 097 @Column(name = "variation_value_2", updatable = true, nullable = true) 098 private Double variationValue2; 099 100 @Column(name = "variation_value_3", updatable = true, nullable = true) 101 private Double variationValue3; 102 103 @Column(name = "variation_value_4", updatable = true, nullable = true) 104 private Double variationValue4; 105 106 @Column(name = "variation_value_5", updatable = true, nullable = true) 107 private Double variationValue5; 108 109 @Column(name = "url", updatable = true, nullable = true, length = 2000) 110 private String url; 111 112 @OneToMany(mappedBy = "measure", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}) 113 private List<MeasureData> measureData = new ArrayList<MeasureData>(); 114 115 @ManyToOne(fetch = FetchType.EAGER) 116 @JoinColumn(name = "characteristic_id") 117 private Characteristic characteristic; 118 119 @Column(name = "person_id", updatable = true, nullable = true) 120 private Integer personId; 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() && !measureData.isEmpty()) { 363 return measureData.get(0).getText(); 364 } 365 return null; 366 } 367 368 /** 369 * Sets the measure data 370 */ 371 public final void setData(String data) { 372 if (data == null) { 373 this.textValue = null; 374 measureData.clear(); 375 376 } else { 377 if (data.length() > TEXT_VALUE_LENGTH) { 378 measureData.clear(); 379 measureData.add(new MeasureData(this, data)); 380 381 } else { 382 this.textValue = data; 383 } 384 } 385 } 386 387 /** 388 * Use getData() instead 389 */ 390 public MeasureData getMeasureData() { 391 if (!measureData.isEmpty()) { 392 return measureData.get(0); 393 } 394 return null; 395 } 396 397 /** 398 * Use setData() instead 399 */ 400 //@Deprecated 401 public void setMeasureData(MeasureData data) { 402 measureData.clear(); 403 if (data != null) { 404 this.measureData.add(data); 405 } 406 } 407 408 /** 409 * @return the text of the alert 410 */ 411 public String getAlertText() { 412 return alertText; 413 } 414 415 /** 416 * Sets the text for the alert 417 */ 418 public void setAlertText(String alertText) { 419 this.alertText = alertText; 420 } 421 422 /** 423 * @return the measure URL 424 */ 425 public String getUrl() { 426 return url; 427 } 428 429 /** 430 * Sets the measure URL 431 */ 432 public void setUrl(String url) { 433 this.url = url; 434 } 435 436 @Override 437 public String toString() { 438 return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString(); 439 } 440 441 public Double getVariationValue1() { 442 return variationValue1; 443 } 444 445 public void setVariationValue1(Double d) { 446 this.variationValue1 = d; 447 } 448 449 public Double getVariationValue2() { 450 return variationValue2; 451 } 452 453 public void setVariationValue2(Double d) { 454 this.variationValue2 = d; 455 } 456 457 public Double getVariationValue3() { 458 return variationValue3; 459 } 460 461 public void setVariationValue3(Double d) { 462 this.variationValue3 = d; 463 } 464 465 public Double getVariationValue4() { 466 return variationValue4; 467 } 468 469 public void setVariationValue4(Double d) { 470 this.variationValue4 = d; 471 } 472 473 public Double getVariationValue5() { 474 return variationValue5; 475 } 476 477 public void setVariationValue5(Double d) { 478 this.variationValue5 = d; 479 } 480 481 /** 482 * Saves the current object to database 483 * 484 * @return the current object 485 */ 486 public MeasureModel save(DatabaseSession session) { 487 MeasureData data = getMeasureData(); 488 setMeasureData(null); 489 session.save(this); 490 491 if (data != null) { 492 data.setMeasure(session.getEntity(MeasureModel.class, getId())); 493 data.setSnapshotId(snapshotId); 494 session.save(data); 495 setMeasureData(data); 496 } 497 return this; 498 } 499 500 public Characteristic getCharacteristic() { 501 return characteristic; 502 } 503 504 public MeasureModel setCharacteristic(Characteristic c) { 505 this.characteristic = c; 506 return this; 507 } 508 509 public Integer getPersonId() { 510 return personId; 511 } 512 513 public MeasureModel setPersonId(Integer i) { 514 this.personId = i; 515 return this; 516 } 517 518 @Override 519 public Object clone() { 520 MeasureModel clone = new MeasureModel(); 521 clone.setMetricId(getMetricId()); 522 clone.setDescription(getDescription()); 523 clone.setTextValue(getTextValue()); 524 clone.setAlertStatus(getAlertStatus()); 525 clone.setAlertText(getAlertText()); 526 clone.setTendency(getTendency()); 527 clone.setVariationValue1(getVariationValue1()); 528 clone.setVariationValue2(getVariationValue2()); 529 clone.setVariationValue3(getVariationValue3()); 530 clone.setVariationValue4(getVariationValue4()); 531 clone.setVariationValue5(getVariationValue5()); 532 clone.setValue(getValue()); 533 clone.setRulePriority(getRulePriority()); 534 clone.setRuleId(getRuleId()); 535 clone.setSnapshotId(getSnapshotId()); 536 clone.setMeasureDate(getMeasureDate()); 537 clone.setUrl(getUrl()); 538 clone.setCharacteristic(getCharacteristic()); 539 clone.setPersonId(getPersonId()); 540 return clone; 541 } 542 543 }