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