001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
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.builder.ToStringBuilder;
023 import org.sonar.api.qualitymodel.Characteristic;
024
025 import java.math.BigDecimal;
026 import java.math.RoundingMode;
027 import java.util.Date;
028
029 /**
030 * A class to handle measures.
031 * <p/>
032 *
033 * @since 1.10
034 */
035 public class Measure {
036 protected static final int MAX_TEXT_SIZE = 96;
037
038 /**
039 * Default precision when saving a float type metric
040 */
041 public final static int DEFAULT_PRECISION = 1;
042
043 private Long id; // for internal use
044 protected Metric metric;
045 protected Double value;
046 protected String data;
047 protected String description;
048 protected Metric.Level alertStatus;
049 protected String alertText;
050 protected Integer tendency;
051 protected Date date;
052 protected Double diff1, diff2, diff3;
053 protected String url;
054 protected Characteristic characteristic;
055 protected PersistenceMode persistenceMode = PersistenceMode.FULL;
056
057 /**
058 * Creates a measure with a metric
059 *
060 * @param metric the metric
061 */
062 public Measure(Metric metric) {
063 this.metric = metric;
064 }
065
066 /**
067 * Creates a measure with a metric and a value
068 *
069 * @param metric the metric
070 * @param value its value
071 */
072 public Measure(Metric metric, Double value) {
073 this.metric = metric;
074 setValue(value);
075 }
076
077 /**
078 * Creates a measure with a metric, a value and a precision for the value
079 *
080 * @param metric the metric
081 * @param value its value
082 * @param precision the value precision
083 */
084 public Measure(Metric metric, Double value, int precision) {
085 this.metric = metric;
086 setValue(value, precision);
087 }
088
089 /**
090 * Creates a measure with a metric, a value and a data field
091 *
092 * @param metric the metric
093 * @param value the value
094 * @param data the data field
095 */
096 public Measure(Metric metric, Double value, String data) {
097 this.metric = metric;
098 setValue(value);
099 setData(data);
100 }
101
102 /**
103 * * Creates a measure with a metric and a data field
104 *
105 * @param metric the metric
106 * @param data the data field
107 */
108 public Measure(Metric metric, String data) {
109 this.metric = metric;
110 setData(data);
111 }
112
113 /**
114 * Creates a measure with a metric and an alert level
115 *
116 * @param metric the metric
117 * @param level the alert level
118 */
119 public Measure(Metric metric, Metric.Level level) {
120 this.metric = metric;
121 if (level != null) {
122 this.data = level.toString();
123 }
124 }
125
126 /**
127 * Creates an empty measure
128 */
129 public Measure() {
130 }
131
132 /**
133 * Gets the persistence mode of the measure. Default persistence mode is FULL,
134 * except when instantiating the measure with a String parameter.
135 */
136 public PersistenceMode getPersistenceMode() {
137 return persistenceMode;
138 }
139
140 /**
141 * <p>Sets the persistence mode of a measure.</p>
142 * <p><b>WARNING : </b>Being able to reuse measures saved in memory is only possible within the same tree.
143 * In a multi-module project for example, a measure save in memory at the module level will not be accessible by
144 * the root project. In that case, database should be used.
145 * </p>
146 *
147 * @param mode the mode
148 * @return the measure object instance
149 */
150 public Measure setPersistenceMode(PersistenceMode mode) {
151 this.persistenceMode = mode;
152 return this;
153 }
154
155 /**
156 * @return return the measures underlying metric
157 */
158 public Metric getMetric() {
159 return metric;
160 }
161
162 /**
163 * Set the underlying metric
164 *
165 * @param metric the metric
166 * @return the measure object instance
167 */
168 public Measure setMetric(Metric metric) {
169 this.metric = metric;
170 return this;
171 }
172
173 /**
174 * @return transforms and returns the data fields as a level of alert
175 */
176 public Metric.Level getDataAsLevel() {
177 if (data != null) {
178 return Metric.Level.valueOf(data);
179 }
180 return null;
181 }
182
183 /**
184 * @return the date of the measure, i.e. the date the measure was taken. Used only in TimeMachine queries
185 */
186 public Date getDate() {
187 return date;
188 }
189
190 /**
191 * Sets the date of the measure - Used only in TimeMachine queries
192 *
193 * @param date the date
194 * @return the measure object instance
195 */
196 public Measure setDate(Date date) {
197 this.date = date;
198 return this;
199 }
200
201 /**
202 * @return the value of the measure as a double
203 */
204 public Double getValue() {
205 return value;
206 }
207
208 /**
209 * @return the value of the measure as an int
210 */
211 public Integer getIntValue() {
212 if (value == null) {
213 return null;
214 }
215 return value.intValue();
216 }
217
218 /**
219 * Sets the measure value with the default precision of 1
220 *
221 * @param v the measure value
222 * @return the measure object instance
223 */
224 public Measure setValue(Double v) {
225 return setValue(v, DEFAULT_PRECISION);
226 }
227
228 /**
229 * Sets the measure value as an int
230 *
231 * @param i the value
232 * @return the measure object instance
233 */
234 public Measure setIntValue(Integer i) {
235 if (i == null) {
236 this.value = null;
237 } else {
238 this.value = Double.valueOf(i);
239 }
240 return this;
241 }
242
243 /**
244 * Sets the measure value with a given precision
245 *
246 * @param v the measure value
247 * @param precision the measure value precision
248 * @return the measure object instance
249 */
250 public Measure setValue(Double v, int precision) {
251 if (v != null) {
252 if (Double.isNaN(v)) {
253 throw new IllegalArgumentException("Measure value can not be NaN");
254 }
255 this.value = scaleValue(v, precision);
256 } else {
257 this.value = null;
258 }
259 return this;
260 }
261
262 private double scaleValue(double value, int scale) {
263 BigDecimal bd = BigDecimal.valueOf(value);
264 return bd.setScale(scale, RoundingMode.HALF_UP).doubleValue();
265 }
266
267 /**
268 * @return the data field of the measure
269 */
270 public String getData() {
271 return data;
272 }
273
274 /**
275 * Sets the data field of the measure.
276 *
277 * @param s the data
278 * @return the measure object instance
279 */
280 public Measure setData(String s) {
281 if (s != null && s.length() >= MAX_TEXT_SIZE && !metric.isDataType()) {
282 throw new IllegalArgumentException("Data is too long for non-data metric : size=" + s.length() + ", max=" + MAX_TEXT_SIZE);
283 }
284 this.data = s;
285 return this;
286 }
287
288 /**
289 * Sets an alert level as the data field
290 *
291 * @param level the alert level
292 * @return the measure object instance
293 */
294 public Measure setData(Metric.Level level) {
295 if (level == null) {
296 this.data = null;
297 } else {
298 this.data = level.toString();
299 }
300 return this;
301 }
302
303 /**
304 * @return the description of the measure
305 */
306 public String getDescription() {
307 return description;
308 }
309
310 /**
311 * Sets the measure description
312 *
313 * @param description the description
314 * @return the measure object instance
315 */
316 public Measure setDescription(String description) {
317 this.description = description;
318 return this;
319 }
320
321 /**
322 * @return the alert status of the measure
323 */
324 public Metric.Level getAlertStatus() {
325 return alertStatus;
326 }
327
328 /**
329 * Set the alert status of the measure
330 *
331 * @param status the status
332 * @return the measure object instance
333 */
334 public Measure setAlertStatus(Metric.Level status) {
335 this.alertStatus = status;
336 return this;
337 }
338
339 /**
340 * @return the text associated to the alert on the measure
341 */
342 public String getAlertText() {
343 return alertText;
344 }
345
346 /**
347 * Sets the text associated to the alert on the measure
348 *
349 * @param alertText the text
350 * @return the measure object instance
351 */
352 public Measure setAlertText(String alertText) {
353 this.alertText = alertText;
354 return this;
355 }
356
357 /**
358 * Gets the measure tendency
359 *
360 * @return the tendency
361 */
362 public Integer getTendency() {
363 return tendency;
364 }
365
366 /**
367 * Sets the tendency for the measure
368 *
369 * @param tendency the tendency
370 * @return the measure object instance
371 */
372 public Measure setTendency(Integer tendency) {
373 this.tendency = tendency;
374 return this;
375 }
376
377 /**
378 * @return the measure id - Internal use only
379 */
380 public Long getId() {
381 return id;
382 }
383
384 /**
385 * Sets the measure id - Internal use only
386 *
387 * @param id the id
388 * @return the measure object instance
389 */
390 public Measure setId(Long id) {
391 this.id = id;
392 return this;
393 }
394
395 /**
396 * @return the first differential value of the measure
397 */
398 public Double getDiffValue1() {
399 return diff1;
400 }
401
402 /**
403 * Sets the first differential value of the measure
404 *
405 * @param diff1 the diff
406 * @return the measure object instance
407 */
408 public Measure setDiffValue1(Double diff1) {
409 this.diff1 = diff1;
410 return this;
411 }
412
413 /**
414 * @return the second differential value of the measure
415 */
416 public Double getDiffValue2() {
417 return diff2;
418 }
419
420 /**
421 * Sets the second differential value of the measure
422 *
423 * @param diff2 the diff
424 * @return the measure object instance
425 */
426 public Measure setDiffValue2(Double diff2) {
427 this.diff2 = diff2;
428 return this;
429 }
430
431 /**
432 * @return the third differential value of the measure
433 */
434 public Double getDiffValue3() {
435 return diff3;
436 }
437
438 /**
439 * Sets the third differential value of the measure
440 *
441 * @param diff3 the diff
442 * @return the measure object instance
443 */
444 public Measure setDiffValue3(Double diff3) {
445 this.diff3 = diff3;
446 return this;
447 }
448
449 /**
450 * @return the url of the measure
451 */
452 public String getUrl() {
453 return url;
454 }
455
456 /**
457 * Sets the URL of the measure
458 *
459 * @param url the url
460 * @return the measure object instance
461 */
462 public Measure setUrl(String url) {
463 this.url = url;
464 return this;
465 }
466
467 public final Characteristic getCharacteristic() {
468 return characteristic;
469 }
470
471 public final Measure setCharacteristic(Characteristic characteristic) {
472 this.characteristic = characteristic;
473 return this;
474 }
475
476
477 // @Override
478 // public boolean equals(Object obj) {
479 // if (!(obj.getClass().equals(Measure.class))) {
480 // return false;
481 // }
482 // if (this == obj) {
483 // return true;
484 // }
485 // Measure rhs = (Measure) obj;
486 // return new EqualsBuilder()
487 // .append(metric, rhs.getMetric())
488 // .append(characteristic, rhs.getCharacteristic())
489 // .isEquals();
490 // }
491 //
492 // @Override
493 // public int hashCode() {
494 // return (metric != null ? metric.hashCode() : 0);
495 // }
496 //
497
498
499 @Override
500 public boolean equals(Object o) {
501 if (this == o) {
502 return true;
503 }
504 if (!(o.getClass().equals(Measure.class))) {
505 return false;
506 }
507
508 Measure measure = (Measure) o;
509 if (metric != null ? !metric.equals(measure.metric) : measure.metric != null) {
510 return false;
511 }
512 if (characteristic != null ? !characteristic.equals(measure.characteristic) : measure.characteristic != null) {
513 return false;
514 }
515 return true;
516 }
517
518 @Override
519 public int hashCode() {
520 int result = metric != null ? metric.hashCode() : 0;
521 result = 31 * result + (characteristic != null ? characteristic.hashCode() : 0);
522 return result;
523 }
524
525 @Override
526 public String toString() {
527 return new ToStringBuilder(this).
528 append("id", id).
529 append("metric", metric).
530 append("value", value).
531 append("data", data).
532 append("description", description).
533 append("alertStatus", alertStatus).
534 append("alertText", alertText).
535 append("tendency", tendency).
536 append("characteristic", characteristic).
537 append("diff1", diff1).
538 append("diff2", diff2).
539 append("diff3", diff3).
540 toString();
541 }
542
543 public boolean hasOptionalData() {
544 return getAlertStatus() != null ||
545 getAlertText() != null ||
546 getDescription() != null ||
547 getDiffValue1() != null ||
548 getDiffValue2() != null ||
549 getDiffValue3() != null ||
550 getData() != null ||
551 getTendency() != null ||
552 getUrl() != null;
553 }
554 }