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