--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.db.createdb;
+
+import com.google.common.collect.Streams;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.jetbrains.annotations.NotNull;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.BranchDto;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.component.SnapshotTesting;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.db.project.ProjectDto;
+import org.sonar.db.rule.RuleDto;
+
+import static org.sonar.db.component.BranchType.BRANCH;
+
+public class PopulateDb {
+ public static void main(String[] args) {
+ final DbTester dbTester = createDbTester();
+
+ // read base data
+ final Map<String, MetricDto> metricDtosByKey;
+ final List<ProjectDto> allProjects;
+ final Set<RuleDto> enabledRules;
+
+ DbSession initSession = dbTester.getSession();
+ metricDtosByKey = dbTester.getDbClient().metricDao().selectAll(initSession).stream().collect(
+ Collectors.toMap(MetricDto::getKey, Function.identity())
+ );
+ allProjects = dbTester.getDbClient().projectDao().selectProjects(initSession);
+ enabledRules = new HashSet<>(dbTester.getDbClient().ruleDao().selectEnabled(dbTester.getSession()));
+
+ generateProject(new SqContext(enabledRules, metricDtosByKey, dbTester),
+ new ProjectStructure("project " + (allProjects.size() + 1), 10, 10, 10, 2, 5));
+
+ // close database connexion
+ dbTester.getDbClient().getDatabase().stop();
+ }
+
+ private record SqContext(Set<RuleDto> rules, Map<String, MetricDto> metricDtosByKey, DbTester dbTester) {
+ public RuleDto findNotSecurityHotspotRule() {
+ return rules.stream().filter(r -> r.getType() != RuleType.SECURITY_HOTSPOT.getDbConstant()).findAny().orElseThrow();
+ }
+ }
+
+ private static @NotNull DbTester createDbTester() {
+ System.setProperty("sonar.jdbc.url", "jdbc:postgresql://localhost:5432/sonarqube");
+ System.setProperty("sonar.jdbc.username", "sonarqube");
+ System.setProperty("sonar.jdbc.password", "sonarqube");
+ System.setProperty("sonar.jdbc.dialect", "postgresql");
+
+ return DbTester.create(System2.INSTANCE);
+ }
+
+ private record ProjectStructure(String projectName, int branchPerProject, int filePerBranch, int issuePerFile, int issueChangePerIssue,
+ int snapshotPerBranch) {
+ }
+
+ private record BranchAndComponentDto(BranchDto branch, ComponentDto compo) {
+ }
+
+ private static ProjectDto generateProject(SqContext sqContext, ProjectStructure pj) {
+ ComponentDto projectCompoDto = sqContext.dbTester.components().insertPublicProject(p -> p.setName(pj.projectName));
+ ProjectDto projectDto = sqContext.dbTester.components().getProjectDto(projectCompoDto);
+
+
+ Streams.concat(
+ // main branch
+ Stream.of(new BranchAndComponentDto(
+ sqContext.dbTester.getDbClient().branchDao().selectByBranchKey(sqContext.dbTester.getSession(), projectDto.getUuid(), "main").orElseThrow(),
+ projectCompoDto)),
+ // other branches
+ Stream.generate(() -> {
+ var branchDto = ComponentTesting.newBranchDto(projectDto.getUuid(), BRANCH);
+ return new BranchAndComponentDto(
+ branchDto,
+ sqContext.dbTester.components().insertProjectBranch(projectDto, branchDto)
+ );
+ }))
+ // until there are enough branches generated
+ .limit(pj.branchPerProject)
+ // for every branche (main included)
+ .forEach(branchAndComponentDto -> {
+ // for every file in branch
+ for (int file = 0; file < pj.filePerBranch; file++) {
+ ComponentDto fileComponentDto = sqContext.dbTester.components().insertFile(branchAndComponentDto.compo);
+ // for every issue in file
+ for (int issue = 0; issue < pj.issuePerFile; issue++) {
+ IssueDto issueDto = sqContext.dbTester.issues().insertIssue(sqContext.findNotSecurityHotspotRule(), branchAndComponentDto.compo, fileComponentDto);
+ // for every issue change in issue
+ for (int issueChange = 0; issueChange < pj.issueChangePerIssue; issueChange++) {
+ sqContext.dbTester.issues().insertChange(issueDto);
+ }
+ }
+ // create live measure for this file
+ fileLiveMeasureMetrics.stream()
+ .map(sqContext.metricDtosByKey::get)
+ .forEach(metricDto -> sqContext.dbTester().measures().insertLiveMeasureWithSensibleValues(fileComponentDto, metricDto));
+ }
+
+ // create live measure for the branch
+ projectLiveMeasureMetrics.stream()
+ .map(sqContext.metricDtosByKey::get)
+ .forEach(metricDto -> sqContext.dbTester().measures().insertLiveMeasureWithSensibleValues(branchAndComponentDto.compo, metricDto));
+
+ long time = System2.INSTANCE.now();
+ List<SnapshotDto> snapshots = new ArrayList<>();
+ // for every snapshot on the current branch
+ for (int snapshot = 0; snapshot < pj.snapshotPerBranch; snapshot++) {
+ SnapshotDto snapshotDto = SnapshotTesting.newAnalysis(branchAndComponentDto.branch);
+ snapshotDto.setLast(false);
+ snapshotDto.setCreatedAt(time);
+ time -= 10_000_000;
+ snapshots.add(snapshotDto);
+ // insert project measure for the snapshot
+ projectProjectMeasureMetrics.stream()
+ .map(sqContext.metricDtosByKey::get)
+ .forEach(metricDto -> sqContext.dbTester().measures().insertMeasureWithSensibleValues(branchAndComponentDto.compo, snapshotDto, metricDto));
+ }
+ SnapshotDto lastSnapshotDto = snapshots.get(0);
+ lastSnapshotDto.setLast(true);
+ sqContext.dbTester.components().insertSnapshots(snapshots.toArray(new SnapshotDto[0]));
+ });
+
+ return projectDto;
+ }
+
+ private static final List<String> projectLiveMeasureMetrics = List.of(
+ CoreMetrics.LINES_KEY,
+ CoreMetrics.NCLOC_KEY,
+ CoreMetrics.NEW_LINES_KEY,
+ CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY,
+ CoreMetrics.CLASSES_KEY,
+ CoreMetrics.FILES_KEY,
+ CoreMetrics.FUNCTIONS_KEY,
+ CoreMetrics.STATEMENTS_KEY,
+ CoreMetrics.COMMENT_LINES_KEY,
+ CoreMetrics.COMMENT_LINES_DENSITY_KEY,
+ CoreMetrics.COMPLEXITY_KEY,
+ CoreMetrics.COGNITIVE_COMPLEXITY_KEY,
+ CoreMetrics.COVERAGE_KEY,
+ CoreMetrics.LINES_TO_COVER_KEY,
+ CoreMetrics.NEW_LINES_TO_COVER_KEY,
+ CoreMetrics.NEW_UNCOVERED_LINES_KEY,
+ CoreMetrics.LINE_COVERAGE_KEY,
+ CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY,
+ CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY,
+ CoreMetrics.DUPLICATED_LINES_KEY,
+ CoreMetrics.NEW_DUPLICATED_LINES_KEY,
+ CoreMetrics.UNCOVERED_LINES_KEY,
+ CoreMetrics.DUPLICATED_BLOCKS_KEY,
+ CoreMetrics.NEW_BLOCKS_DUPLICATED_KEY,
+ CoreMetrics.DUPLICATED_FILES_KEY,
+ CoreMetrics.DUPLICATED_LINES_DENSITY_KEY,
+ CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY,
+ CoreMetrics.VIOLATIONS_KEY,
+ CoreMetrics.BLOCKER_VIOLATIONS_KEY,
+ CoreMetrics.CRITICAL_VIOLATIONS_KEY,
+ CoreMetrics.MAJOR_VIOLATIONS_KEY,
+ CoreMetrics.MINOR_VIOLATIONS_KEY,
+ CoreMetrics.INFO_VIOLATIONS_KEY,
+ CoreMetrics.NEW_VIOLATIONS_KEY,
+ CoreMetrics.NEW_BLOCKER_VIOLATIONS_KEY,
+ CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY,
+ CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY,
+ CoreMetrics.NEW_MINOR_VIOLATIONS_KEY,
+ CoreMetrics.NEW_INFO_VIOLATIONS_KEY,
+ CoreMetrics.FALSE_POSITIVE_ISSUES_KEY,
+ CoreMetrics.WONT_FIX_ISSUES_KEY,
+ CoreMetrics.OPEN_ISSUES_KEY,
+ CoreMetrics.REOPENED_ISSUES_KEY,
+ CoreMetrics.CONFIRMED_ISSUES_KEY,
+ CoreMetrics.CODE_SMELLS_KEY,
+ CoreMetrics.NEW_CODE_SMELLS_KEY,
+ CoreMetrics.BUGS_KEY,
+ CoreMetrics.NEW_BUGS_KEY,
+ CoreMetrics.VULNERABILITIES_KEY,
+ CoreMetrics.NEW_VULNERABILITIES_KEY,
+ CoreMetrics.SECURITY_HOTSPOTS_KEY,
+ CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY,
+ CoreMetrics.TECHNICAL_DEBT_KEY,
+ CoreMetrics.NEW_TECHNICAL_DEBT_KEY,
+ CoreMetrics.SQALE_RATING_KEY,
+ CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY,
+ CoreMetrics.DEVELOPMENT_COST_KEY,
+ CoreMetrics.NEW_DEVELOPMENT_COST_KEY,
+ CoreMetrics.SQALE_DEBT_RATIO_KEY,
+ CoreMetrics.NEW_SQALE_DEBT_RATIO_KEY,
+ CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
+ CoreMetrics.RELIABILITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.RELIABILITY_RATING_KEY,
+ CoreMetrics.NEW_RELIABILITY_RATING_KEY,
+ CoreMetrics.SECURITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.SECURITY_RATING_KEY,
+ CoreMetrics.NEW_SECURITY_RATING_KEY,
+ CoreMetrics.SECURITY_REVIEW_RATING_KEY,
+ CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY,
+ CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY,
+ CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY,
+ CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY,
+ CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY,
+ CoreMetrics.ALERT_STATUS_KEY,
+ CoreMetrics.QUALITY_GATE_DETAILS_KEY,
+ CoreMetrics.LAST_COMMIT_DATE_KEY,
+ CoreMetrics.ANALYSIS_FROM_SONARQUBE_9_4_KEY
+ );
+
+ private static final List<String> fileLiveMeasureMetrics = List.of(
+ CoreMetrics.LINE_COVERAGE_KEY,
+ CoreMetrics.COMMENT_LINES_KEY,
+ CoreMetrics.VIOLATIONS_KEY,
+ CoreMetrics.LAST_COMMIT_DATE_KEY,
+ CoreMetrics.MAJOR_VIOLATIONS_KEY,
+ CoreMetrics.DEVELOPMENT_COST_KEY,
+ CoreMetrics.FUNCTIONS_KEY,
+ CoreMetrics.VULNERABILITIES_KEY,
+ CoreMetrics.EXECUTABLE_LINES_DATA_KEY,
+ CoreMetrics.TECHNICAL_DEBT_KEY,
+ CoreMetrics.LINES_KEY,
+ CoreMetrics.CODE_SMELLS_KEY,
+ CoreMetrics.UNCOVERED_LINES_KEY,
+ CoreMetrics.COVERAGE_KEY,
+ CoreMetrics.SQALE_RATING_KEY,
+ CoreMetrics.COGNITIVE_COMPLEXITY_KEY,
+ CoreMetrics.NCLOC_KEY,
+ CoreMetrics.STATEMENTS_KEY,
+ CoreMetrics.COMMENT_LINES_DENSITY_KEY,
+ CoreMetrics.LINES_TO_COVER_KEY,
+ CoreMetrics.CLASSES_KEY,
+ CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
+ CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY,
+ CoreMetrics.NCLOC_DATA_KEY,
+ CoreMetrics.RELIABILITY_RATING_KEY,
+ CoreMetrics.MINOR_VIOLATIONS_KEY,
+ CoreMetrics.SECURITY_REVIEW_RATING_KEY,
+ CoreMetrics.BLOCKER_VIOLATIONS_KEY,
+ CoreMetrics.SQALE_DEBT_RATIO_KEY,
+ CoreMetrics.COMPLEXITY_KEY,
+ CoreMetrics.SECURITY_RATING_KEY,
+ CoreMetrics.OPEN_ISSUES_KEY,
+ CoreMetrics.SECURITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.FILES_KEY,
+ CoreMetrics.NEW_DUPLICATED_LINES_KEY,
+ CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY,
+ CoreMetrics.NEW_BLOCKS_DUPLICATED_KEY,
+ CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY,
+ CoreMetrics.NEW_LINES_TO_COVER_KEY,
+ CoreMetrics.NEW_UNCOVERED_LINES_KEY,
+ CoreMetrics.NEW_LINES_KEY
+ );
+
+ private static final List<String> projectProjectMeasureMetrics = List.of(
+ CoreMetrics.LINE_COVERAGE_KEY,
+ CoreMetrics.COMMENT_LINES_KEY,
+ CoreMetrics.VIOLATIONS_KEY,
+ CoreMetrics.LAST_COMMIT_DATE_KEY,
+ CoreMetrics.MAJOR_VIOLATIONS_KEY,
+ CoreMetrics.DUPLICATED_FILES_KEY,
+ CoreMetrics.DEVELOPMENT_COST_KEY,
+ CoreMetrics.INFO_VIOLATIONS_KEY,
+ CoreMetrics.FUNCTIONS_KEY,
+ CoreMetrics.VULNERABILITIES_KEY,
+ CoreMetrics.ANALYSIS_FROM_SONARQUBE_9_4_KEY,
+ CoreMetrics.FALSE_POSITIVE_ISSUES_KEY,
+ CoreMetrics.CRITICAL_VIOLATIONS_KEY,
+ CoreMetrics.TECHNICAL_DEBT_KEY,
+ CoreMetrics.LINES_KEY,
+ CoreMetrics.RELIABILITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.CODE_SMELLS_KEY,
+ CoreMetrics.UNCOVERED_LINES_KEY,
+ CoreMetrics.COVERAGE_KEY,
+ CoreMetrics.SQALE_RATING_KEY,
+ CoreMetrics.COGNITIVE_COMPLEXITY_KEY,
+ CoreMetrics.DUPLICATED_BLOCKS_KEY,
+ CoreMetrics.NCLOC_KEY,
+ CoreMetrics.STATEMENTS_KEY,
+ CoreMetrics.SECURITY_HOTSPOTS_KEY,
+ CoreMetrics.COMMENT_LINES_DENSITY_KEY,
+ CoreMetrics.BUGS_KEY,
+ CoreMetrics.LINES_TO_COVER_KEY,
+ CoreMetrics.CLASSES_KEY,
+ CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A_KEY,
+ CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY,
+ CoreMetrics.RELIABILITY_RATING_KEY,
+ CoreMetrics.MINOR_VIOLATIONS_KEY,
+ CoreMetrics.DUPLICATED_LINES_DENSITY_KEY,
+ CoreMetrics.WONT_FIX_ISSUES_KEY,
+ CoreMetrics.SECURITY_REVIEW_RATING_KEY,
+ CoreMetrics.BLOCKER_VIOLATIONS_KEY,
+ CoreMetrics.CONFIRMED_ISSUES_KEY,
+ CoreMetrics.DUPLICATED_LINES_KEY,
+ CoreMetrics.ALERT_STATUS_KEY,
+ CoreMetrics.SQALE_DEBT_RATIO_KEY,
+ CoreMetrics.COMPLEXITY_KEY,
+ CoreMetrics.SECURITY_RATING_KEY,
+ CoreMetrics.OPEN_ISSUES_KEY,
+ CoreMetrics.SECURITY_REMEDIATION_EFFORT_KEY,
+ CoreMetrics.QUALITY_GATE_DETAILS_KEY,
+ CoreMetrics.REOPENED_ISSUES_KEY,
+ CoreMetrics.FILES_KEY
+ );
+}
*/
package org.sonar.db.measure;
+import java.time.Instant;
+import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import org.apache.commons.lang.math.RandomUtils;
+import org.sonar.api.measures.CoreMetrics;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.metric.MetricDto;
.setData(String.valueOf(cursor++))
.setValue((double) cursor++);
}
+
+ public static LiveMeasureDto createLiveMeasure(MetricDto metricDto, ComponentDto componentDto) {
+ BiConsumer<MetricDto, MeasureAdapter> populator = specificLiveMeasurePopulator.getOrDefault(metricDto.getKey(), defaultLiveMeasurePopulator);
+ LiveMeasureDto liveMeasureDto = newLiveMeasure(componentDto, metricDto);
+ populator.accept(metricDto, new MeasureAdapter(liveMeasureDto));
+ return liveMeasureDto;
+ }
+
+ public static MeasureDto createProjectMeasure(MetricDto metricDto, SnapshotDto snapshotDto, ComponentDto projectComponentDto) {
+ BiConsumer<MetricDto, MeasureAdapter> populator = specificLiveMeasurePopulator.getOrDefault(metricDto.getKey(), defaultLiveMeasurePopulator);
+ MeasureDto measureDto = newMeasureDto(metricDto, projectComponentDto, snapshotDto);
+ populator.accept(metricDto, new MeasureAdapter(measureDto));
+ return measureDto;
+ }
+
+ private static final Consumer<MeasureAdapter> ratingMeasurePopulator =
+ m -> {
+ int rating = ThreadLocalRandom.current().nextInt(1, 5);
+ char textValue = (char) ('A' + rating - 1);
+ m.setValue((double) rating).setData("" + textValue);
+ };
+
+ private static final Map<String, BiConsumer<MetricDto, MeasureAdapter>> specificLiveMeasurePopulator = Map.of(
+ CoreMetrics.DEVELOPMENT_COST_KEY, (metric, m) -> m.setData("" + Math.round(ThreadLocalRandom.current().nextDouble(100, 10_000))),
+ CoreMetrics.LAST_COMMIT_DATE_KEY, (metric, m) -> m.setValue((double)
+ Instant.now().minusSeconds(Math.round(ThreadLocalRandom.current().nextDouble(100_000, 1_000_000))).toEpochMilli()),
+ CoreMetrics.SQALE_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m),
+ CoreMetrics.RELIABILITY_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m),
+ CoreMetrics.SECURITY_REVIEW_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m),
+ CoreMetrics.SECURITY_RATING_KEY, (metric, m) -> ratingMeasurePopulator.accept(m),
+ CoreMetrics.ALERT_STATUS_KEY, (metric, m) -> {
+ boolean isOk = ThreadLocalRandom.current().nextDouble() > 0.5;
+ m.setData(isOk ? "OK" : "ERROR");
+ m.setAlert(isOk ? "OK" : "ERROR");
+ },
+ CoreMetrics.QUALITY_GATE_DETAILS_KEY, (metric, m) -> m.setData("{\"level\":\"OK\"}")
+ );
+
+ private static final BiConsumer<MetricDto, MeasureAdapter> defaultLiveMeasurePopulator =
+ (metric, m) -> {
+ int min, max;
+ if (metric.getWorstValue() != null && metric.getBestValue() != null) {
+ min = (int) Math.min(metric.getBestValue(), metric.getWorstValue());
+ max = (int) Math.max(metric.getBestValue(), metric.getWorstValue());
+ } else if (metric.getDirection() != 0) {
+ int worst, best;
+ if (metric.getWorstValue() != null) {
+ worst = metric.getWorstValue().intValue();
+ best = -metric.getDirection() * 100;
+ } else if (metric.getBestValue() != null) {
+ best = metric.getBestValue().intValue();
+ worst = best - metric.getDirection() * 100;
+ } else {
+ worst = 0;
+ best = -metric.getDirection() * 100;
+ }
+ min = Math.min(best, worst);
+ max = Math.max(best, worst);
+ } else {
+ min = 0;
+ max = 100;
+ }
+
+ m.setValue((double) Math.round(ThreadLocalRandom.current().nextDouble(min, max)));
+ };
+
+ private static class MeasureAdapter {
+ private final MeasureDto projectMeasure;
+ private final LiveMeasureDto liveMeasure;
+
+ private MeasureAdapter(LiveMeasureDto liveMeasure) {
+ this.projectMeasure = null;
+ this.liveMeasure = liveMeasure;
+ }
+
+ private MeasureAdapter(MeasureDto projectMeasure) {
+ this.projectMeasure = projectMeasure;
+ this.liveMeasure = null;
+ }
+
+ public MeasureAdapter setValue(Double value) {
+ if (projectMeasure != null) {
+ projectMeasure.setValue(value);
+ } else if (liveMeasure != null) {
+ liveMeasure.setValue(value);
+ }
+ return this;
+ }
+
+ public MeasureAdapter setData(String data) {
+ if (projectMeasure != null) {
+ projectMeasure.setData(data);
+ } else if (liveMeasure != null) {
+ liveMeasure.setData(data);
+ }
+ return this;
+ }
+
+ public MeasureAdapter setAlert(String value) {
+ if (projectMeasure != null) {
+ projectMeasure.setAlertText(value).setAlertStatus(value);
+ }
+ return this;
+ }
+ }
}