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 */ 020package org.sonar.api.database.model; 021 022import com.google.common.base.Charsets; 023import com.google.common.base.Throwables; 024import org.apache.commons.lang.builder.ReflectionToStringBuilder; 025import org.apache.commons.lang.builder.ToStringStyle; 026import org.sonar.api.database.DatabaseSession; 027import org.sonar.api.measures.Metric; 028import org.sonar.api.rules.RulePriority; 029 030import javax.persistence.Column; 031import javax.persistence.Entity; 032import javax.persistence.EnumType; 033import javax.persistence.Enumerated; 034import javax.persistence.GeneratedValue; 035import javax.persistence.Id; 036import javax.persistence.Table; 037import java.io.UnsupportedEncodingException; 038 039/** 040 * This class is the Hibernate model to store a measure in the DB 041 */ 042@Entity 043@Table(name = "project_measures") 044public class MeasureModel implements Cloneable { 045 046 public static final int TEXT_VALUE_LENGTH = 4000; 047 048 @Id 049 @Column(name = "id") 050 @GeneratedValue 051 private Long id; 052 053 @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20) 054 private Double value = 0.0; 055 056 @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH) 057 private String textValue; 058 059 @Column(name = "tendency", updatable = true, nullable = true) 060 private Integer tendency; 061 062 @Column(name = "metric_id", updatable = false, nullable = false) 063 private Integer metricId; 064 065 @Column(name = "snapshot_id", updatable = true, nullable = true) 066 private Integer snapshotId; 067 068 @Column(name = "project_id", updatable = true, nullable = true) 069 private Integer projectId; 070 071 @Column(name = "description", updatable = true, nullable = true, length = 4000) 072 private String description; 073 074 @Column(name = "rule_id", updatable = true, nullable = true) 075 private Integer ruleId; 076 077 @Column(name = "rule_priority", updatable = false, nullable = true) 078 @Enumerated(EnumType.ORDINAL) 079 private RulePriority rulePriority; 080 081 @Column(name = "alert_status", updatable = true, nullable = true, length = 5) 082 private String alertStatus; 083 084 @Column(name = "alert_text", updatable = true, nullable = true, length = 4000) 085 private String alertText; 086 087 @Column(name = "variation_value_1", updatable = true, nullable = true) 088 private Double variationValue1; 089 090 @Column(name = "variation_value_2", updatable = true, nullable = true) 091 private Double variationValue2; 092 093 @Column(name = "variation_value_3", updatable = true, nullable = true) 094 private Double variationValue3; 095 096 @Column(name = "variation_value_4", updatable = true, nullable = true) 097 private Double variationValue4; 098 099 @Column(name = "variation_value_5", updatable = true, nullable = true) 100 private Double variationValue5; 101 102 @Column(name = "url", updatable = true, nullable = true, length = 2000) 103 private String url; 104 105 @Column(name = "characteristic_id", nullable = true) 106 private Integer characteristicId; 107 108 @Column(name = "person_id", updatable = true, nullable = true) 109 private Integer personId; 110 111 @Column(name = "measure_data", updatable = true, nullable = true, length = 167772150) 112 private byte[] data; 113 114 /** 115 * Creates a measure based on a metric and a double value 116 */ 117 public MeasureModel(int metricId, Double val) { 118 if (val.isNaN() || val.isInfinite()) { 119 throw new IllegalArgumentException("Measure value is NaN. Metric=" + metricId); 120 } 121 this.metricId = metricId; 122 this.value = val; 123 } 124 125 /** 126 * Creates a measure based on a metric and an alert level 127 */ 128 public MeasureModel(int metricId, Metric.Level level) { 129 this.metricId = metricId; 130 if (level != null) { 131 this.textValue = level.toString(); 132 } 133 } 134 135 /** 136 * Creates a measure based on a metric and a string value 137 */ 138 public MeasureModel(int metricId, String val) { 139 this.metricId = metricId; 140 setData(val); 141 } 142 143 /** 144 * Creates an empty measure 145 */ 146 public MeasureModel() { 147 } 148 149 public Long getId() { 150 return id; 151 } 152 153 public void setId(Long id) { 154 this.id = id; 155 } 156 157 /** 158 * @return the measure double value 159 */ 160 public Double getValue() { 161 return value; 162 } 163 164 /** 165 * Sets the measure value 166 * 167 * @throws IllegalArgumentException in case value is not a valid double 168 */ 169 public MeasureModel setValue(Double value) { 170 if (value != null && (value.isNaN() || value.isInfinite())) { 171 throw new IllegalArgumentException(); 172 } 173 this.value = value; 174 return this; 175 } 176 177 /** 178 * @return the measure description 179 */ 180 public String getDescription() { 181 return description; 182 } 183 184 /** 185 * Sets the measure description 186 */ 187 public void setDescription(String description) { 188 this.description = description; 189 } 190 191 /** 192 * @return the measure alert level 193 */ 194 public Metric.Level getLevelValue() { 195 if (textValue != null) { 196 return Metric.Level.valueOf(textValue); 197 } 198 return null; 199 } 200 201 /** 202 * Use getData() instead 203 */ 204 public String getTextValue() { 205 return textValue; 206 } 207 208 /** 209 * Use setData() instead 210 */ 211 public void setTextValue(String textValue) { 212 this.textValue = textValue; 213 } 214 215 /** 216 * @return the measure tendency 217 */ 218 public Integer getTendency() { 219 return tendency; 220 } 221 222 /** 223 * Sets the measure tendency 224 * 225 * @return the current object 226 */ 227 public MeasureModel setTendency(Integer tendency) { 228 this.tendency = tendency; 229 return this; 230 } 231 232 /** 233 * @return whether the measure is about rule 234 */ 235 public boolean isRuleMeasure() { 236 return ruleId != null || rulePriority != null; 237 } 238 239 public Integer getMetricId() { 240 return metricId; 241 } 242 243 public void setMetricId(Integer metricId) { 244 this.metricId = metricId; 245 } 246 247 /** 248 * @return the snapshot id the measure is attached to 249 */ 250 public Integer getSnapshotId() { 251 return snapshotId; 252 } 253 254 /** 255 * Sets the snapshot id 256 * 257 * @return the current object 258 */ 259 public MeasureModel setSnapshotId(Integer snapshotId) { 260 this.snapshotId = snapshotId; 261 return this; 262 } 263 264 public Integer getRuleId() { 265 return ruleId; 266 } 267 268 /** 269 * Sets the rule for the measure 270 * 271 * @return the current object 272 */ 273 public MeasureModel setRuleId(Integer ruleId) { 274 this.ruleId = ruleId; 275 return this; 276 } 277 278 /** 279 * @return the rule priority 280 */ 281 public RulePriority getRulePriority() { 282 return rulePriority; 283 } 284 285 /** 286 * Sets the rule priority 287 */ 288 public void setRulePriority(RulePriority rulePriority) { 289 this.rulePriority = rulePriority; 290 } 291 292 /** 293 * @return the project id 294 */ 295 public Integer getProjectId() { 296 return projectId; 297 } 298 299 /** 300 * Sets the project id 301 */ 302 public void setProjectId(Integer projectId) { 303 this.projectId = projectId; 304 } 305 306 /** 307 * @return the alert status if there is one, null otherwise 308 */ 309 public Metric.Level getAlertStatus() { 310 if (alertStatus == null) { 311 return null; 312 } 313 return Metric.Level.valueOf(alertStatus); 314 } 315 316 /** 317 * Sets the measure alert status 318 * 319 * @return the current object 320 */ 321 public MeasureModel setAlertStatus(Metric.Level level) { 322 if (level != null) { 323 this.alertStatus = level.toString(); 324 } else { 325 this.alertStatus = null; 326 } 327 return this; 328 } 329 330 /** 331 * @return the measure data 332 */ 333 public String getData(Metric metric) { 334 if (this.textValue != null) { 335 return this.textValue; 336 } 337 if (metric.isDataType() && data != null) { 338 try { 339 return new String(data, Charsets.UTF_8.name()); 340 } catch (UnsupportedEncodingException e) { 341 // how is it possible to not support UTF-8 ? 342 Throwables.propagate(e); 343 } 344 } 345 return null; 346 } 347 348 /** 349 * Sets the measure data 350 */ 351 public final void setData(String data) { 352 if (data == null) { 353 this.textValue = null; 354 this.data = null; 355 356 } else { 357 if (data.length() > TEXT_VALUE_LENGTH) { 358 this.textValue = null; 359 this.data = data.getBytes(Charsets.UTF_8); 360 } else { 361 this.textValue = data; 362 this.data = null; 363 } 364 } 365 } 366 367 /** 368 * @return the text of the alert 369 */ 370 public String getAlertText() { 371 return alertText; 372 } 373 374 /** 375 * Sets the text for the alert 376 */ 377 public void setAlertText(String alertText) { 378 this.alertText = alertText; 379 } 380 381 /** 382 * @return the measure URL 383 */ 384 public String getUrl() { 385 return url; 386 } 387 388 /** 389 * Sets the measure URL 390 */ 391 public void setUrl(String url) { 392 this.url = url; 393 } 394 395 @Override 396 public String toString() { 397 return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString(); 398 } 399 400 public Double getVariationValue1() { 401 return variationValue1; 402 } 403 404 public void setVariationValue1(Double d) { 405 this.variationValue1 = d; 406 } 407 408 public Double getVariationValue2() { 409 return variationValue2; 410 } 411 412 public void setVariationValue2(Double d) { 413 this.variationValue2 = d; 414 } 415 416 public Double getVariationValue3() { 417 return variationValue3; 418 } 419 420 public void setVariationValue3(Double d) { 421 this.variationValue3 = d; 422 } 423 424 public Double getVariationValue4() { 425 return variationValue4; 426 } 427 428 public void setVariationValue4(Double d) { 429 this.variationValue4 = d; 430 } 431 432 public Double getVariationValue5() { 433 return variationValue5; 434 } 435 436 public void setVariationValue5(Double d) { 437 this.variationValue5 = d; 438 } 439 440 /** 441 * Saves the current object to database 442 * 443 * @return the current object 444 */ 445 public MeasureModel save(DatabaseSession session) { 446 session.save(this); 447 return this; 448 } 449 450 public Integer getCharacteristicId() { 451 return characteristicId; 452 } 453 454 public MeasureModel setCharacteristicId(Integer characteristicId) { 455 this.characteristicId = characteristicId; 456 return this; 457 } 458 459 public Integer getPersonId() { 460 return personId; 461 } 462 463 public MeasureModel setPersonId(Integer i) { 464 this.personId = i; 465 return this; 466 } 467 468 @Override 469 public Object clone() { 470 MeasureModel clone = new MeasureModel(); 471 clone.setMetricId(getMetricId()); 472 clone.setDescription(getDescription()); 473 clone.setTextValue(getTextValue()); 474 clone.setAlertStatus(getAlertStatus()); 475 clone.setAlertText(getAlertText()); 476 clone.setTendency(getTendency()); 477 clone.setVariationValue1(getVariationValue1()); 478 clone.setVariationValue2(getVariationValue2()); 479 clone.setVariationValue3(getVariationValue3()); 480 clone.setVariationValue4(getVariationValue4()); 481 clone.setVariationValue5(getVariationValue5()); 482 clone.setValue(getValue()); 483 clone.setRulePriority(getRulePriority()); 484 clone.setRuleId(getRuleId()); 485 clone.setSnapshotId(getSnapshotId()); 486 clone.setUrl(getUrl()); 487 clone.setCharacteristicId(getCharacteristicId()); 488 clone.setPersonId(getPersonId()); 489 return clone; 490 } 491 492}