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