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
127      public Metric() {
128      }
129    
130      /**
131       * Creates a metric based on its key. Shortcut to Metric(key, ValueType.INT)
132       *
133       * @param key the metric key
134       * @deprecated since 2.7 use the Builder factory.
135       */
136      @Deprecated
137      public Metric(String key) {
138        this(key, ValueType.INT);
139      }
140    
141      /**
142       * Creates a metric based on a key and a type. Shortcut to
143       * Metric(key, key, key, type, -1, Boolean.FALSE, null, false)
144       *
145       * @param key  the key
146       * @param type the type
147       * @deprecated since 2.7 use the Builder factory.
148       */
149      @Deprecated
150      public Metric(String key, ValueType type) {
151        this(key, key, key, type, -1, Boolean.FALSE, null, false);
152      }
153    
154      /**
155       * @deprecated since 2.7 use the Builder factory.
156       */
157      @Deprecated
158      public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain) {
159        this(key, name, description, type, direction, qualitative, domain, false);
160      }
161    
162      /**
163       * Creates a fully qualified metric. This defaults some values:
164       * <ul>
165       * <li>origin : Origin.JAV</li>
166       * </ul>
167       *
168       * @param key         the metric key
169       * @param name        the metric name
170       * @param description the metric description
171       * @param type        the metric type
172       * @param direction   the metric direction
173       * @param qualitative whether the metric is qualitative
174       * @param domain      the metric domain
175       * @param userManaged whether the metric is user managed
176       * @deprecated since 2.7 use the Builder factory.
177       */
178      @Deprecated
179      public Metric(String key, String name, String description, ValueType type, Integer direction, Boolean qualitative, String domain, boolean userManaged) {
180        this.key = key;
181        this.description = description;
182        this.type = type;
183        this.direction = direction;
184        this.domain = domain;
185        this.name = name;
186        this.qualitative = qualitative;
187        this.userManaged = userManaged;
188        this.origin = Origin.JAV;
189        if (ValueType.PERCENT.equals(this.type)) {
190          this.bestValue = (direction == DIRECTION_BETTER ? 100.0 : 0.0);
191          this.worstValue = (direction == DIRECTION_BETTER ? 0.0 : 100.0);
192        }
193      }
194    
195      /**
196       * Creates a fully qualified metric. This defaults some values:
197       * <ul>
198       * <li>origin : Origin.JAV</li>
199       * <li>enabled : true</li>
200       * <li>userManaged : true</li>
201       * </ul>
202       *
203       * @param key         the metric key
204       * @param name        the metric name
205       * @param type        the metric type
206       * @param direction   the metric direction
207       * @param qualitative whether the metric is qualitative
208       * @param domain      the metric domain
209       * @param formula     the metric formula
210       * @deprecated since 2.7 use the Builder factory.
211       */
212      @Deprecated
213      public Metric(String key, String name, ValueType type, Integer direction, Boolean qualitative, String domain, Formula formula) {
214        this.key = key;
215        this.name = name;
216        this.type = type;
217        this.direction = direction;
218        this.domain = domain;
219        this.qualitative = qualitative;
220        this.origin = Origin.JAV;
221        this.enabled = true;
222        this.userManaged = false;
223        this.formula = formula;
224        if (ValueType.PERCENT.equals(this.type)) {
225          this.bestValue = (direction == DIRECTION_BETTER ? 100.0 : 0.0);
226          this.worstValue = (direction == DIRECTION_BETTER ? 0.0 : 100.0);
227        }
228      }
229    
230      private Metric(String key, String name, ValueType type, String description, Integer direction, String domain, Boolean qualitative, Double worstValue, Double bestValue, Boolean optimizedBestValue, Boolean hidden, Formula formula) {
231        this.key = key;
232        this.name = name;
233        this.description = description;
234        this.type = type;
235        this.direction = direction;
236        this.domain = domain;
237        this.qualitative = qualitative;
238        this.userManaged = Boolean.FALSE;
239        this.enabled = Boolean.TRUE;
240        this.worstValue = worstValue;
241        this.optimizedBestValue = optimizedBestValue;
242        this.bestValue = bestValue;
243        this.hidden = hidden;
244        this.formula = formula;
245      }
246    
247      /**
248       * For internal use only
249       */
250      public Integer getId() {
251        return id;
252      }
253    
254      /**
255       * For internal use only
256       */
257      public Metric setId(Integer id) {
258        this.id = id;
259        return this;
260      }
261    
262    
263      /**
264       * @return the metric formula
265       */
266      public Formula getFormula() {
267        return formula;
268      }
269    
270      /**
271       * Sets the metric formula
272       *
273       * @param formula the formula
274       * @return this
275       */
276      public Metric setFormula(Formula formula) {
277        this.formula = formula;
278        return this;
279      }
280    
281      /**
282       * @return wether the metric is qualitative
283       */
284      public Boolean getQualitative() {
285        return qualitative;
286      }
287    
288      /**
289       * Sets whether the metric is qualitative
290       *
291       * @param qualitative whether the metric is qualitative
292       * @return this
293       */
294      public Metric setQualitative(Boolean qualitative) {
295        this.qualitative = qualitative;
296        return this;
297      }
298    
299      /**
300       * @return the metric key
301       */
302      public String getKey() {
303        return key;
304      }
305    
306      /**
307       * Sets the metric key
308       *
309       * @param key the key
310       * @return this
311       */
312      public Metric setKey(String key) {
313        this.key = key;
314        return this;
315      }
316    
317      /**
318       * @return the metric type
319       */
320      public ValueType getType() {
321        return type;
322      }
323    
324      /**
325       * Sets the metric type
326       *
327       * @param type the type
328       * @return this
329       */
330      public Metric setType(ValueType type) {
331        this.type = type;
332        return this;
333      }
334    
335      /**
336       * @return the metric description
337       */
338      public String getDescription() {
339        return description;
340      }
341    
342      /**
343       * Sets the metric description
344       *
345       * @param description the description
346       * @return this
347       */
348      public Metric setDescription(String description) {
349        this.description = description;
350        return this;
351      }
352    
353      /**
354       * @return whether the metric is a managed by the users (manual metric)
355       */
356      public Boolean getUserManaged() {
357        return userManaged;
358      }
359    
360      /**
361       * Sets whether the metric is user managed
362       *
363       * @param userManaged whether the metric is user managed
364       * @return this
365       */
366      public Metric setUserManaged(Boolean userManaged) {
367        this.userManaged = userManaged;
368        return this;
369      }
370    
371      /**
372       * @return whether the metric is enabled
373       */
374      public Boolean getEnabled() {
375        return enabled;
376      }
377    
378      /**
379       * Sets whether the metric is enabled
380       *
381       * @param enabled whether the metric is enabled
382       * @return this
383       */
384      public Metric setEnabled(Boolean enabled) {
385        this.enabled = enabled;
386        return this;
387      }
388    
389      /**
390       * @return the metric direction
391       */
392      public Integer getDirection() {
393        return direction;
394      }
395    
396      /**
397       * Sets the metric direction.
398       *
399       * @param direction the direction
400       */
401      public Metric setDirection(Integer direction) {
402        this.direction = direction;
403        return this;
404      }
405    
406      /**
407       * @return the domain of the metric
408       */
409      public String getDomain() {
410        return domain;
411      }
412    
413      /**
414       * Sets the domain for the metric (General, Complexity...)
415       *
416       * @param domain the domain
417       * @return this
418       */
419      public Metric setDomain(String domain) {
420        this.domain = domain;
421        return this;
422      }
423    
424      /**
425       * @return the metric name
426       */
427      public String getName() {
428        return name;
429      }
430    
431      /**
432       * Sets the metric name
433       *
434       * @param name the name
435       * @return this
436       */
437      public Metric setName(String name) {
438        this.name = name;
439        return this;
440      }
441    
442      /**
443       * @return the origin of the metric - Internal use only
444       */
445      public Origin getOrigin() {
446        return origin;
447      }
448    
449      /**
450       * Set the origin of the metric - Internal use only
451       *
452       * @param origin the origin
453       * @return this
454       */
455      public Metric setOrigin(Origin origin) {
456        this.origin = origin;
457        return this;
458      }
459    
460      public Double getWorstValue() {
461        return worstValue;
462      }
463    
464      public Double getBestValue() {
465        return bestValue;
466      }
467    
468      /**
469       * @return this
470       */
471      public Metric setWorstValue(Double d) {
472        this.worstValue = d;
473        return this;
474      }
475    
476      /**
477       * @param bestValue the best value. It can be null.
478       * @return this
479       */
480      public Metric setBestValue(Double bestValue) {
481        this.bestValue = bestValue;
482        return this;
483      }
484    
485      /**
486       * @return whether the metric is of a numeric type (int, percentage...)
487       */
488      public boolean isNumericType() {
489        return ValueType.INT.equals(type)
490            || ValueType.FLOAT.equals(type)
491            || ValueType.PERCENT.equals(type)
492            || ValueType.BOOL.equals(type)
493            || ValueType.MILLISEC.equals(type)
494            || ValueType.RATING.equals(type);
495      }
496    
497      /**
498       * @return whether the metric is of type data
499       */
500      public boolean isDataType() {
501        return ValueType.DATA.equals(type) || ValueType.DISTRIB.equals(type);
502      }
503    
504      /**
505       * @return whether the metric is of type percentage
506       */
507      public boolean isPercentageType() {
508        return ValueType.PERCENT.equals(type);
509      }
510    
511      public Metric setOptimizedBestValue(Boolean b) {
512        this.optimizedBestValue = b;
513        return this;
514      }
515    
516      public Boolean isOptimizedBestValue() {
517        return optimizedBestValue;
518      }
519    
520      public Boolean isHidden() {
521        return hidden;
522      }
523    
524      public Metric setHidden(Boolean hidden) {
525        this.hidden = hidden;
526        return this;
527      }
528    
529      @Override
530      public int hashCode() {
531        return key.hashCode();
532      }
533    
534      @Override
535      public boolean equals(Object obj) {
536        if (!(obj instanceof Metric)) {
537          return false;
538        }
539        if (this == obj) {
540          return true;
541        }
542        Metric other = (Metric) obj;
543        return key.equals(other.getKey());
544      }
545    
546      @Override
547      public String toString() {
548        return new ToStringBuilder(this)
549            .append("key", key)
550            .append("name", name)
551            .append("type", type)
552            .append("enabled", enabled)
553            .append("qualitative", qualitative)
554            .append("direction", direction)
555            .append("domain", domain)
556            .append("worstValue", worstValue)
557            .append("bestValue", bestValue)
558            .append("optimizedBestValue", optimizedBestValue)
559            .append("hidden", hidden)
560            .toString();
561      }
562    
563      /**
564       * Merge with fields from other metric. All fields are copied, except the id.
565       *
566       * @return this
567       */
568      public Metric merge(final Metric with) {
569        this.description = with.description;
570        this.domain = with.domain;
571        this.enabled = with.enabled;
572        this.qualitative = with.qualitative;
573        this.worstValue = with.worstValue;
574        this.bestValue = with.bestValue;
575        this.optimizedBestValue = with.optimizedBestValue;
576        this.direction = with.direction;
577        this.key = with.key;
578        this.type = with.type;
579        this.name = with.name;
580        this.userManaged = with.userManaged;
581        this.origin = with.origin;
582        this.hidden = with.hidden;
583        return this;
584      }
585    
586      public static final class Builder {
587        private String key;
588        private Metric.ValueType type;
589        private String name;
590        private String description;
591        private Integer direction = DIRECTION_NONE;
592        private Boolean qualitative = Boolean.FALSE;
593        private String domain = null;
594        private Formula formula;
595        private Double worstValue;
596        private Double bestValue;
597        private boolean optimizedBestValue = false;
598        private boolean hidden = false;
599    
600        public Builder(String key, String name, ValueType type) {
601          if (StringUtils.isBlank(key)) {
602            throw new IllegalArgumentException("Metric key can not be blank");
603          }
604          if (StringUtils.isBlank(name)) {
605            throw new IllegalArgumentException("Metric name can not be blank");
606          }
607          if (type==null) {
608            throw new IllegalArgumentException("Metric type can not be null");
609          }
610          this.key = key;
611          this.name = name;
612          this.type = type;
613        }
614    
615        public Builder setDescription(String s) {
616          this.description = s;
617          return this;
618        }
619    
620        /**
621         * Used for numeric values only
622         */
623        public Builder setDirection(Integer i) {
624          this.direction = i;
625          return this;
626        }
627    
628        public Builder setQualitative(Boolean b) {
629          this.qualitative = b;
630          return this;
631        }
632    
633        public Builder setDomain(String s) {
634          this.domain = s;
635          return this;
636        }
637    
638        public Builder setFormula(Formula f) {
639          this.formula = f;
640          return this;
641        }
642    
643        public Builder setWorstValue(Double d) {
644          this.worstValue = d;
645          return this;
646        }
647    
648        public Builder setBestValue(Double d) {
649          this.bestValue = d;
650          return this;
651        }
652    
653        public Builder setOptimizedBestValue(boolean b) {
654          this.optimizedBestValue = b;
655          return this;
656        }
657    
658        public Builder setHidden(boolean b) {
659          this.hidden = b;
660          return this;
661        }
662    
663        public Metric create() {
664          return new Metric(key, name, type, description, direction, domain, qualitative, worstValue, bestValue, optimizedBestValue, hidden, formula);
665        }
666      }
667    }