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.database.model;
021
022 import org.apache.commons.lang.builder.ToStringBuilder;
023 import org.hibernate.annotations.Cache;
024 import org.hibernate.annotations.CacheConcurrencyStrategy;
025 import org.sonar.api.database.BaseIdentifiable;
026 import org.sonar.api.database.DatabaseSession;
027 import org.sonar.api.measures.Measure;
028 import org.sonar.api.measures.Metric;
029 import org.sonar.api.measures.RuleMeasure;
030 import org.sonar.api.rules.Rule;
031 import org.sonar.api.rules.RulePriority;
032
033 import java.util.ArrayList;
034 import java.util.Date;
035 import java.util.List;
036 import javax.persistence.*;
037
038 @Entity
039 @Table(name = "project_measures")
040 public class MeasureModel extends BaseIdentifiable implements Cloneable {
041
042 public static final int TEXT_VALUE_LENGTH = 96;
043
044 @Column(name = "value", updatable = true, nullable = true, precision = 30, scale = 20)
045 private Double value = 0.0;
046
047 @Column(name = "text_value", updatable = true, nullable = true, length = TEXT_VALUE_LENGTH)
048 private String textValue;
049
050 @Column(name = "tendency", updatable = true, nullable = true)
051 private Integer tendency;
052
053 @ManyToOne(fetch = FetchType.EAGER)
054 @JoinColumn(name = "metric_id")
055 @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
056 private Metric metric;
057
058 @Column(name = "snapshot_id", updatable = true, nullable = true)
059 private Integer snapshotId;
060
061 @Column(name = "project_id", updatable = true, nullable = true)
062 private Integer projectId;
063
064 @Column(name = "description", updatable = true, nullable = true, length = 4000)
065 private String description;
066
067 @Temporal(TemporalType.TIMESTAMP)
068 @Column(name = "measure_date", updatable = true, nullable = true)
069 private Date measureDate;
070
071 @ManyToOne(fetch = FetchType.LAZY)
072 @JoinColumn(name = "rule_id")
073 @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
074 private Rule rule;
075
076 @Column(name = "rules_category_id")
077 private Integer rulesCategoryId;
078
079 @Column(name = "rule_priority", updatable = false, nullable = true)
080 @Enumerated(EnumType.ORDINAL)
081 private RulePriority rulePriority;
082
083 @Column(name = "alert_status", updatable = true, nullable = true, length = 5)
084 private String alertStatus;
085
086 @Column(name = "alert_text", updatable = true, nullable = true, length = 4000)
087 private String alertText;
088
089 @Column(name = "diff_value_1", updatable = true, nullable = true)
090 private Double diffValue1;
091
092 @Column(name = "diff_value_2", updatable = true, nullable = true)
093 private Double diffValue2;
094
095 @Column(name = "diff_value_3", updatable = true, nullable = true)
096 private Double diffValue3;
097
098 @Column(name = "url", updatable = true, nullable = true, length = 2000)
099 private String url;
100
101 @OneToMany(mappedBy = "measure", fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
102 private List<MeasureData> measureData = new ArrayList<MeasureData>();
103
104 public MeasureModel(Metric metric, Double val) {
105 if (val.isNaN() || val.isInfinite()) {
106 throw new IllegalArgumentException("Measure value is NaN. Metric=" + metric);
107 }
108 this.metric = metric;
109 this.value = val;
110 }
111
112 public MeasureModel(Metric metric, Metric.Level level) {
113 this.metric = metric;
114 if (level != null) {
115 this.textValue = level.toString();
116 }
117 }
118
119 public MeasureModel(Metric metric, String val) {
120 this.metric = metric;
121 setData(val);
122 }
123
124 public MeasureModel() {
125 }
126
127 public Double getValue() {
128 return value;
129 }
130
131 public String getDescription() {
132 return description;
133 }
134
135 public void setDescription(String description) {
136 this.description = description;
137 }
138
139 public MeasureModel setValue(Double value) throws IllegalArgumentException {
140 if (value != null && (value.isNaN() || value.isInfinite())) {
141 throw new IllegalArgumentException();
142 }
143 this.value = value;
144 return this;
145 }
146
147 public Metric.Level getLevelValue() {
148 if (textValue != null) {
149 return Metric.Level.valueOf(textValue);
150 }
151 return null;
152 }
153
154 /**
155 * Use getData() instead
156 */
157 public String getTextValue() {
158 return textValue;
159 }
160
161 /**
162 * Use setData() instead
163 */
164 public void setTextValue(String textValue) {
165 this.textValue = textValue;
166 }
167
168 public Integer getTendency() {
169 return tendency;
170 }
171
172 public boolean isRuleMeasure() {
173 return rule != null || rulePriority != null || rulesCategoryId != null;
174 }
175
176 public MeasureModel setTendency(Integer tendency) {
177 this.tendency = tendency;
178 return this;
179 }
180
181 public Metric getMetric() {
182 return metric;
183 }
184
185 public void setMetric(Metric metric) {
186 this.metric = metric;
187 }
188
189 public Integer getSnapshotId() {
190 return snapshotId;
191 }
192
193 public MeasureModel setSnapshotId(Integer snapshotId) {
194 this.snapshotId = snapshotId;
195 return this;
196 }
197
198 public Rule getRule() {
199 return rule;
200 }
201
202 public MeasureModel setRule(Rule rule) {
203 this.rule = rule;
204 return this;
205 }
206
207 public Integer getRulesCategoryId() {
208 return rulesCategoryId;
209 }
210
211 public MeasureModel setRulesCategoryId(Integer id) {
212 this.rulesCategoryId = id;
213 return this;
214 }
215
216 public RulePriority getRulePriority() {
217 return rulePriority;
218 }
219
220 public void setRulePriority(RulePriority rulePriority) {
221 this.rulePriority = rulePriority;
222 }
223
224 public Integer getProjectId() {
225 return projectId;
226 }
227
228 public void setProjectId(Integer projectId) {
229 this.projectId = projectId;
230 }
231
232 public Date getMeasureDate() {
233 return measureDate;
234 }
235
236 public MeasureModel setMeasureDate(Date measureDate) {
237 this.measureDate = measureDate;
238 return this;
239 }
240
241 public Metric.Level getAlertStatus() {
242 if (alertStatus == null) {
243 return null;
244 }
245 return Metric.Level.valueOf(alertStatus);
246 }
247
248 public MeasureModel setAlertStatus(Metric.Level level) {
249 if (level != null) {
250 this.alertStatus = level.toString();
251 } else {
252 this.alertStatus = null;
253 }
254 return this;
255 }
256
257 public String getData() {
258 if (this.textValue != null) {
259 return this.textValue;
260 }
261 if (metric.isDataType() && !measureData.isEmpty()) {
262 return measureData.get(0).getText();
263 }
264 return null;
265 }
266
267 public void setData(String data) {
268 if (data == null) {
269 this.textValue = null;
270 measureData.clear();
271
272 } else {
273 if (data.length() > TEXT_VALUE_LENGTH) {
274 measureData.clear();
275 measureData.add(new MeasureData(this, data));
276
277 } else {
278 this.textValue = data;
279 }
280 }
281 }
282
283 /**
284 * Use getData() instead
285 */
286 public MeasureData getMeasureData() {
287 if (!measureData.isEmpty()) {
288 return measureData.get(0);
289 }
290 return null;
291 }
292
293 /**
294 * Use setData() instead
295 */
296 //@Deprecated
297 public void setMeasureData(MeasureData data) {
298 measureData.clear();
299 if (data != null) {
300 this.measureData.add(data);
301 }
302 }
303
304 public String getAlertText() {
305 return alertText;
306 }
307
308 public void setAlertText(String alertText) {
309 this.alertText = alertText;
310 }
311
312 public String getUrl() {
313 return url;
314 }
315
316 public void setUrl(String url) {
317 this.url = url;
318 }
319
320 @Override
321 public String toString() {
322 return new ToStringBuilder(this).
323 append("value", value).
324 append("metric", metric).
325 toString();
326 }
327
328 public Integer getRuleId() {
329 if (getRule() != null) {
330 return getRule().getId();
331 }
332 return null;
333 }
334
335 public Double getDiffValue1() {
336 return diffValue1;
337 }
338
339 public void setDiffValue1(Double diffValue1) {
340 this.diffValue1 = diffValue1;
341 }
342
343 public Double getDiffValue2() {
344 return diffValue2;
345 }
346
347 public void setDiffValue2(Double diffValue2) {
348 this.diffValue2 = diffValue2;
349 }
350
351 public Double getDiffValue3() {
352 return diffValue3;
353 }
354
355 public void setDiffValue3(Double diffValue3) {
356 this.diffValue3 = diffValue3;
357 }
358
359 public MeasureModel save(DatabaseSession session) {
360 this.metric = session.reattach(Metric.class, metric.getId());
361 MeasureData data = getMeasureData();
362 setMeasureData(null);
363 session.save(this);
364
365 if (data != null) {
366 data.setMeasure(session.getEntity(MeasureModel.class, getId()));
367 data.setSnapshotId(snapshotId);
368 session.save(data);
369 setMeasureData(data);
370 }
371 return this;
372 }
373
374 @Override
375 public Object clone() {
376 MeasureModel clone = new MeasureModel();
377 clone.setMetric(getMetric());
378 clone.setDescription(getDescription());
379 clone.setTextValue(getTextValue());
380 clone.setAlertStatus(getAlertStatus());
381 clone.setAlertText(getAlertText());
382 clone.setTendency(getTendency());
383 clone.setDiffValue1(getDiffValue1());
384 clone.setDiffValue2(getDiffValue2());
385 clone.setDiffValue3(getDiffValue3());
386 clone.setValue(getValue());
387 clone.setRulesCategoryId(getRulesCategoryId());
388 clone.setRulePriority(getRulePriority());
389 clone.setRule(getRule());
390 clone.setSnapshotId(getSnapshotId());
391 clone.setMeasureDate(getMeasureDate());
392 clone.setUrl(getUrl());
393 return clone;
394 }
395
396 public static MeasureModel build(Measure measure) {
397 return build(measure, new MeasureModel());
398 }
399
400 public static MeasureModel build(Measure measure, MeasureModel merge) {
401 merge.setMetric(measure.getMetric());
402 merge.setDescription(measure.getDescription());
403 merge.setData(measure.getData());
404 merge.setAlertStatus(measure.getAlertStatus());
405 merge.setAlertText(measure.getAlertText());
406 merge.setTendency(measure.getTendency());
407 merge.setDiffValue1(measure.getDiffValue1());
408 merge.setDiffValue2(measure.getDiffValue2());
409 merge.setDiffValue3(measure.getDiffValue3());
410 merge.setUrl(measure.getUrl());
411 if (measure.getValue() != null) {
412 merge.setValue(measure.getValue().doubleValue());
413 } else {
414 merge.setValue(null);
415 }
416 if (measure instanceof RuleMeasure) {
417 RuleMeasure ruleMeasure = (RuleMeasure) measure;
418 merge.setRulesCategoryId(ruleMeasure.getRuleCategory());
419 merge.setRulePriority(ruleMeasure.getRulePriority());
420 merge.setRule(ruleMeasure.getRule());
421 }
422 return merge;
423 }
424
425 public Measure toMeasure() {
426 Measure measure;
427 if (isRuleMeasure()) {
428 measure = new RuleMeasure(getMetric(), getRule(), getRulePriority(), getRulesCategoryId());
429 } else {
430 measure = new Measure(getMetric());
431 }
432 measure.setId(getId());
433 measure.setDescription(getDescription());
434 measure.setValue(getValue());
435 measure.setData(getData());
436 measure.setAlertStatus(getAlertStatus());
437 measure.setAlertText(getAlertText());
438 measure.setTendency(getTendency());
439 measure.setDiffValue1(getDiffValue1());
440 measure.setDiffValue2(getDiffValue2());
441 measure.setDiffValue3(getDiffValue3());
442 measure.setUrl(getUrl());
443 return measure;
444 }
445
446 public static List<Measure> toMeasures(List<MeasureModel> models) {
447 List<Measure> result = new ArrayList<Measure>();
448 for (MeasureModel model : models) {
449 if (model != null) {
450 result.add(model.toMeasure());
451 }
452 }
453 return result;
454 }
455 }