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