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.measures; 021 022 import org.apache.commons.lang.StringUtils; 023 import org.apache.commons.lang.builder.ToStringBuilder; 024 import org.sonar.api.BatchExtension; 025 import org.sonar.api.ServerExtension; 026 027 import javax.persistence.*; 028 029 /** 030 * @since 1.10 031 */ 032 @Table(name = "metrics") 033 @Entity(name = "Metric") 034 public class Metric implements ServerExtension, BatchExtension { 035 036 /** 037 * A metric bigger value means a degradation 038 */ 039 public final static int DIRECTION_WORST = -1; 040 /** 041 * A metric bigger value means an improvement 042 */ 043 public final static int DIRECTION_BETTER = 1; 044 /** 045 * The metric direction has no meaning 046 */ 047 public final static int DIRECTION_NONE = 0; 048 049 public enum ValueType { 050 INT, FLOAT, PERCENT, BOOL, STRING, MILLISEC, DATA, LEVEL, DISTRIB, RATING 051 } 052 053 public enum Level { 054 OK("Green"), WARN("Orange"), ERROR("Red"); 055 056 private String colorName; 057 058 Level(String colorName) { 059 this.colorName = colorName; 060 } 061 062 public String getColorName() { 063 return colorName; 064 } 065 } 066 067 public enum Origin { 068 JAV, GUI, WS 069 } 070 071 @Id 072 @Column(name = "id") 073 @GeneratedValue 074 private Integer id; 075 076 @Transient 077 private Formula formula; 078 079 @Column(name = "name", updatable = false, nullable = false, length = 64) 080 private String key; 081 082 @Column(name = "description", updatable = true, nullable = true, length = 255) 083 private String description; 084 085 @Column(name = "val_type", updatable = true, nullable = true) 086 @Enumerated(EnumType.STRING) 087 private ValueType type; 088 089 @Column(name = "direction", updatable = true, nullable = true) 090 private Integer direction; 091 092 @Column(name = "domain", updatable = true, nullable = true, length = 60) 093 private String domain; 094 095 @Column(name = "short_name", updatable = true, nullable = true, length = 64) 096 private String name; 097 098 @Column(name = "qualitative", updatable = true, nullable = true) 099 private Boolean qualitative = Boolean.FALSE; 100 101 @Column(name = "user_managed", updatable = true, nullable = true) 102 private Boolean userManaged = Boolean.FALSE; 103 104 @Column(name = "enabled", updatable = true, nullable = true) 105 private Boolean enabled = Boolean.TRUE; 106 107 @Column(name = "origin", updatable = true, nullable = true, length = 3) 108 @Enumerated(EnumType.STRING) 109 private Origin origin = Origin.JAV; 110 111 @Column(name = "worst_value", updatable = true, nullable = true, precision = 30, scale = 20) 112 private Double worstValue; 113 114 @Column(name = "best_value", updatable = true, nullable = true, precision = 30, scale = 20) 115 private Double bestValue; 116 117 @Column(name = "optimized_best_value", updatable = true, nullable = true) 118 private Boolean optimizedBestValue; 119 120 @Column(name = "hidden", updatable = true, nullable = true) 121 private Boolean hidden = Boolean.FALSE; 122 123 /** 124 * Creates an empty metric 125 * 126 * @deprecated in 1.12. Use the {@link Builder} factory. 127 */ 128 @Deprecated 129 public Metric() { 130 } 131 132 /** 133 * Creates a metric based on its key. Shortcut to Metric(key, ValueType.INT) 134 * 135 * @param key the metric key 136 * @deprecated since 2.7 use the {@link Builder} factory. 137 */ 138 @Deprecated 139 public Metric(String key) { 140 this(key, ValueType.INT); 141 } 142 143 /** 144 * Creates a metric based on a key and a type. Shortcut to 145 * Metric(key, key, key, type, -1, Boolean.FALSE, null, false) 146 * 147 * @param key the key 148 * @param type the type 149 * @deprecated since 2.7 use the {@link Builder} factory. 150 */ 151 @Deprecated 152 public Metric(String key, ValueType type) { 153 this(key, key, key, type, -1, Boolean.FALSE, null, false); 154 } 155 156 /** 157 * @deprecated since 2.7 use the {@link Builder} factory. 158 */ 159 @Deprecated 160 public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain) { 161 this(key, name, description, type, direction, qualitative, domain, false); 162 } 163 164 /** 165 * Creates a fully qualified metric. This defaults some values: 166 * <ul> 167 * <li>origin : Origin.JAV</li> 168 * </ul> 169 * 170 * @param key the metric key 171 * @param name the metric name 172 * @param description the metric description 173 * @param type the metric type 174 * @param direction the metric direction 175 * @param qualitative whether the metric is qualitative 176 * @param domain the metric domain 177 * @param userManaged whether the metric is user managed 178 * @deprecated since 2.7 use the {@link Builder} factory. 179 */ 180 @Deprecated 181 public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain, boolean userManaged) { 182 this.key = key; 183 this.description = description; 184 this.type = type; 185 this.direction = direction; 186 this.domain = domain; 187 this.name = name; 188 this.qualitative = qualitative; 189 this.userManaged = userManaged; 190 this.origin = Origin.JAV; 191 if (ValueType.PERCENT.equals(this.type)) { 192 this.bestValue = (direction == DIRECTION_BETTER ? 100.0 : 0.0); 193 this.worstValue = (direction == DIRECTION_BETTER ? 0.0 : 100.0); 194 } 195 } 196 197 /** 198 * Creates a fully qualified metric. This defaults some values: 199 * <ul> 200 * <li>origin : Origin.JAV</li> 201 * <li>enabled : true</li> 202 * <li>userManaged : true</li> 203 * </ul> 204 * 205 * @param key the metric key 206 * @param name the metric name 207 * @param type the metric type 208 * @param direction the metric direction 209 * @param qualitative whether the metric is qualitative 210 * @param domain the metric domain 211 * @param formula the metric formula 212 * @deprecated since 2.7 use the {@link Builder} factory. 213 */ 214 @Deprecated 215 public Metric(String key, String name, ValueType type, Integer direction, Boolean qualitative, String domain, Formula formula) { 216 this.key = key; 217 this.name = name; 218 this.type = type; 219 this.direction = direction; 220 this.domain = domain; 221 this.qualitative = qualitative; 222 this.origin = Origin.JAV; 223 this.enabled = true; 224 this.userManaged = false; 225 this.formula = formula; 226 if (ValueType.PERCENT.equals(this.type)) { 227 this.bestValue = (direction == DIRECTION_BETTER ? 100.0 : 0.0); 228 this.worstValue = (direction == DIRECTION_BETTER ? 0.0 : 100.0); 229 } 230 } 231 232 private Metric(String key, String name, ValueType type, String description, Integer direction, String domain, Boolean qualitative, Double worstValue, Double bestValue, 233 Boolean optimizedBestValue, Boolean hidden, Formula formula, boolean userManaged) { 234 this.key = key; 235 this.name = name; 236 this.description = description; 237 this.type = type; 238 this.direction = direction; 239 this.domain = domain; 240 this.qualitative = qualitative; 241 this.userManaged = Boolean.FALSE; 242 this.enabled = Boolean.TRUE; 243 this.worstValue = worstValue; 244 this.optimizedBestValue = optimizedBestValue; 245 this.bestValue = bestValue; 246 this.hidden = hidden; 247 this.formula = formula; 248 this.userManaged = userManaged; 249 } 250 251 /** 252 * For internal use only 253 */ 254 public Integer getId() { 255 return id; 256 } 257 258 /** 259 * For internal use only 260 */ 261 public Metric setId(Integer id) { 262 this.id = id; 263 return this; 264 } 265 266 /** 267 * @return the metric formula 268 */ 269 public Formula getFormula() { 270 return formula; 271 } 272 273 /** 274 * Sets the metric formula 275 * 276 * @param formula the formula 277 * @return this 278 */ 279 public Metric setFormula(Formula formula) { 280 this.formula = formula; 281 return this; 282 } 283 284 /** 285 * @return wether the metric is qualitative 286 */ 287 public Boolean getQualitative() { 288 return qualitative; 289 } 290 291 /** 292 * Sets whether the metric is qualitative 293 * 294 * @param qualitative whether the metric is qualitative 295 * @return this 296 */ 297 public Metric setQualitative(Boolean qualitative) { 298 this.qualitative = qualitative; 299 return this; 300 } 301 302 /** 303 * @return the metric key 304 */ 305 public String getKey() { 306 return key; 307 } 308 309 /** 310 * Sets the metric key 311 * 312 * @param key the key 313 * @return this 314 */ 315 public Metric setKey(String key) { 316 this.key = key; 317 return this; 318 } 319 320 /** 321 * @return the metric type 322 */ 323 public ValueType getType() { 324 return type; 325 } 326 327 /** 328 * Sets the metric type 329 * 330 * @param type the type 331 * @return this 332 */ 333 public Metric setType(ValueType type) { 334 this.type = type; 335 return this; 336 } 337 338 /** 339 * @return the metric description 340 */ 341 public String getDescription() { 342 return description; 343 } 344 345 /** 346 * Sets the metric description 347 * 348 * @param description the description 349 * @return this 350 */ 351 public Metric setDescription(String description) { 352 this.description = description; 353 return this; 354 } 355 356 /** 357 * @return whether the metric is a managed by the users ("manual metric") 358 */ 359 public Boolean getUserManaged() { 360 return userManaged; 361 } 362 363 /** 364 * Sets whether the metric is managed by users ("manual metric") 365 * 366 * @param userManaged whether the metric is user managed 367 * @return this 368 */ 369 public Metric setUserManaged(Boolean userManaged) { 370 this.userManaged = userManaged; 371 return this; 372 } 373 374 /** 375 * @return whether the metric is enabled 376 */ 377 public Boolean getEnabled() { 378 return enabled; 379 } 380 381 /** 382 * Sets whether the metric is enabled 383 * 384 * @param enabled whether the metric is enabled 385 * @return this 386 */ 387 public Metric setEnabled(Boolean enabled) { 388 this.enabled = enabled; 389 return this; 390 } 391 392 /** 393 * @return the metric direction 394 */ 395 public Integer getDirection() { 396 return direction; 397 } 398 399 /** 400 * Sets the metric direction. 401 * 402 * @param direction the direction 403 */ 404 public Metric setDirection(Integer direction) { 405 this.direction = direction; 406 return this; 407 } 408 409 /** 410 * @return the domain of the metric 411 */ 412 public String getDomain() { 413 return domain; 414 } 415 416 /** 417 * Sets the domain for the metric (General, Complexity...) 418 * 419 * @param domain the domain 420 * @return this 421 */ 422 public Metric setDomain(String domain) { 423 this.domain = domain; 424 return this; 425 } 426 427 /** 428 * @return the metric name 429 */ 430 public String getName() { 431 return name; 432 } 433 434 /** 435 * Sets the metric name 436 * 437 * @param name the name 438 * @return this 439 */ 440 public Metric setName(String name) { 441 this.name = name; 442 return this; 443 } 444 445 /** 446 * @return the origin of the metric - Internal use only 447 */ 448 public Origin getOrigin() { 449 return origin; 450 } 451 452 /** 453 * Set the origin of the metric - Internal use only 454 * 455 * @param origin the origin 456 * @return this 457 */ 458 public Metric setOrigin(Origin origin) { 459 this.origin = origin; 460 return this; 461 } 462 463 public Double getWorstValue() { 464 return worstValue; 465 } 466 467 public Double getBestValue() { 468 return bestValue; 469 } 470 471 /** 472 * @return this 473 */ 474 public Metric setWorstValue(Double d) { 475 this.worstValue = d; 476 return this; 477 } 478 479 /** 480 * @param bestValue the best value. It can be null. 481 * @return this 482 */ 483 public Metric setBestValue(Double bestValue) { 484 this.bestValue = bestValue; 485 return this; 486 } 487 488 /** 489 * @return whether the metric is of a numeric type (int, percentage...) 490 */ 491 public boolean isNumericType() { 492 return ValueType.INT.equals(type) 493 || ValueType.FLOAT.equals(type) 494 || ValueType.PERCENT.equals(type) 495 || ValueType.BOOL.equals(type) 496 || ValueType.MILLISEC.equals(type) 497 || ValueType.RATING.equals(type); 498 } 499 500 /** 501 * @return whether the metric is of type data 502 */ 503 public boolean isDataType() { 504 return ValueType.DATA.equals(type) || ValueType.DISTRIB.equals(type); 505 } 506 507 /** 508 * @return whether the metric is of type percentage 509 */ 510 public boolean isPercentageType() { 511 return ValueType.PERCENT.equals(type); 512 } 513 514 public Metric setOptimizedBestValue(Boolean b) { 515 this.optimizedBestValue = b; 516 return this; 517 } 518 519 public Boolean isOptimizedBestValue() { 520 return optimizedBestValue; 521 } 522 523 public Boolean isHidden() { 524 return hidden; 525 } 526 527 public Metric setHidden(Boolean hidden) { 528 this.hidden = hidden; 529 return this; 530 } 531 532 @Override 533 public int hashCode() { 534 return key.hashCode(); 535 } 536 537 @Override 538 public boolean equals(Object obj) { 539 if (!(obj instanceof Metric)) { 540 return false; 541 } 542 if (this == obj) { 543 return true; 544 } 545 Metric other = (Metric) obj; 546 return key.equals(other.getKey()); 547 } 548 549 @Override 550 public String toString() { 551 return new ToStringBuilder(this) 552 .append("key", key) 553 .append("name", name) 554 .append("type", type) 555 .append("enabled", enabled) 556 .append("qualitative", qualitative) 557 .append("direction", direction) 558 .append("domain", domain) 559 .append("worstValue", worstValue) 560 .append("bestValue", bestValue) 561 .append("optimizedBestValue", optimizedBestValue) 562 .append("hidden", hidden) 563 .toString(); 564 } 565 566 /** 567 * Merge with fields from other metric. All fields are copied, except the id. 568 * 569 * @return this 570 */ 571 public Metric merge(final Metric with) { 572 this.description = with.description; 573 this.domain = with.domain; 574 this.enabled = with.enabled; 575 this.qualitative = with.qualitative; 576 this.worstValue = with.worstValue; 577 this.bestValue = with.bestValue; 578 this.optimizedBestValue = with.optimizedBestValue; 579 this.direction = with.direction; 580 this.key = with.key; 581 this.type = with.type; 582 this.name = with.name; 583 this.userManaged = with.userManaged; 584 this.origin = with.origin; 585 this.hidden = with.hidden; 586 return this; 587 } 588 589 /** 590 * @since 2.7 591 */ 592 public static final class Builder { 593 private String key; 594 private Metric.ValueType type; 595 private String name; 596 private String description; 597 private Integer direction = DIRECTION_NONE; 598 private Boolean qualitative = Boolean.FALSE; 599 private String domain = null; 600 private Formula formula; 601 private Double worstValue; 602 private Double bestValue; 603 private boolean optimizedBestValue = false; 604 private boolean hidden = false; 605 private boolean userManaged = false; 606 607 /** 608 * @param key the metric key, should be unique among all metrics 609 * @param name the metric name 610 * @param type the metric type 611 */ 612 public Builder(String key, String name, ValueType type) { 613 if (StringUtils.isBlank(key)) { 614 throw new IllegalArgumentException("Metric key can not be blank"); 615 } 616 if (StringUtils.isBlank(name)) { 617 throw new IllegalArgumentException("Metric name can not be blank"); 618 } 619 if (type == null) { 620 throw new IllegalArgumentException("Metric type can not be null"); 621 } 622 this.key = key; 623 this.name = name; 624 this.type = type; 625 } 626 627 /** 628 * Sets the metric description. 629 */ 630 public Builder setDescription(String s) { 631 this.description = s; 632 return this; 633 } 634 635 /** 636 * Sets the metric direction. Used for numeric values only. 637 * 638 * @see Metric#DIRECTION_WORST 639 * @see Metric#DIRECTION_BETTER 640 * @see Metric#DIRECTION_NONE 641 */ 642 public Builder setDirection(Integer i) { 643 this.direction = i; 644 return this; 645 } 646 647 /** 648 * Sets whether the metric is qualitative. 649 */ 650 public Builder setQualitative(Boolean b) { 651 this.qualitative = b; 652 return this; 653 } 654 655 /** 656 * Sets the domain for the metric (General, Complexity...). 657 */ 658 public Builder setDomain(String s) { 659 this.domain = s; 660 return this; 661 } 662 663 public Builder setFormula(Formula f) { 664 this.formula = f; 665 return this; 666 } 667 668 /** 669 * Sets the worst value. 670 */ 671 public Builder setWorstValue(Double d) { 672 this.worstValue = d; 673 return this; 674 } 675 676 /** 677 * Sets the best value. Resources would be hidden on drilldown page, if value of measure equal to best value. 678 */ 679 public Builder setBestValue(Double d) { 680 this.bestValue = d; 681 return this; 682 } 683 684 public Builder setOptimizedBestValue(boolean b) { 685 this.optimizedBestValue = b; 686 return this; 687 } 688 689 /** 690 * Sets whether the metric should be hidden in UI (e.g. in Time Machine). 691 */ 692 public Builder setHidden(boolean b) { 693 this.hidden = b; 694 return this; 695 } 696 697 /** 698 * Values of user-managed metrics can be set online in the "Manual measures" page. 699 * @since 2.10 700 */ 701 public boolean isUserManaged() { 702 return userManaged; 703 } 704 705 /** 706 * Values of user-managed metrics can be set online in the "Manual measures" page. 707 * 708 * @since 2.10 709 */ 710 public Builder setUserManaged(boolean b) { 711 this.userManaged = b; 712 return this; 713 } 714 715 public Metric create() { 716 if (ValueType.PERCENT.equals(this.type)) { 717 this.bestValue = (direction == DIRECTION_BETTER ? 100.0 : 0.0); 718 this.worstValue = (direction == DIRECTION_BETTER ? 0.0 : 100.0); 719 } 720 return new Metric(key, name, type, description, direction, domain, qualitative, worstValue, bestValue, optimizedBestValue, hidden, formula, userManaged); 721 } 722 } 723 }