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 }