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