class MetricsDataController {

    private static final Integer METRIC_FULL_LENGTH = 3;

    private final List<AbstractRealTimeDataStorage> realTimeDataStorages;

    private final List<AbstractHistoryDataStorage> historyDataStorages;

    public MetricsDataController(List<AbstractRealTimeDataStorage> realTimeDataStorages,
                                 List<AbstractHistoryDataStorage> historyDataStorages) {
        this.realTimeDataStorages = realTimeDataStorages;
        this.historyDataStorages = historyDataStorages;
    }

    @GetMapping("/api/warehouse/storage/status")
    @Operation(summary = "Query Warehouse Storage Server Status", description = "Query the availability status of the storage service under the warehouse")
    public ResponseEntity<Message<Void>> getWarehouseStorageServerStatus() {
        boolean available = false;
        if (historyDataStorages != null) {
            available = historyDataStorages.stream().anyMatch(AbstractHistoryDataStorage::isServerAvailable);
        }
        if (available) {
            return ResponseEntity.ok(Message.success());
        } else {
            return ResponseEntity.ok(Message.fail(FAIL_CODE, "Service not available!"));
        }
    }

    @GetMapping("/api/monitor/{monitorId}/metrics/{metrics}")
    @Operation(summary = "Query Real Time Metrics Data", description = "Query real-time metrics data of monitoring indicators")
    public ResponseEntity<Message<MetricsData>> getMetricsData(
            @Parameter(description = "Monitor Id", example = "343254354")
            @PathVariable Long monitorId,
            @Parameter(description = "Metrics Name", example = "cpu")
            @PathVariable String metrics) {
        AbstractRealTimeDataStorage realTimeDataStorage = realTimeDataStorages.stream()
                .filter(AbstractRealTimeDataStorage::isServerAvailable)
                .max((o1, o2) -> {
                    if (o1 instanceof RealTimeMemoryDataStorage) {
                        return -1;
                    } else if (o2 instanceof RealTimeMemoryDataStorage) {
                        return 1;
                    } else {
                        return 0;
                    }
                }).orElse(null);
        if (realTimeDataStorage == null) {
            return ResponseEntity.ok(Message.fail(FAIL_CODE, "real time store not available"));
        }
        CollectRep.MetricsData storageData = realTimeDataStorage.getCurrentMetricsData(monitorId, metrics);
        if (storageData == null) {
            return ResponseEntity.ok(Message.success("query metrics data is empty"));
        }
        {
            MetricsData.MetricsDataBuilder dataBuilder = MetricsData.builder();
            dataBuilder.id(storageData.getId()).app(storageData.getApp()).metrics(storageData.getMetrics())
                    .time(storageData.getTime());
            List<Field> fields = storageData.getFieldsList().stream().map(tmpField ->
                            Field.builder().name(tmpField.getName())
                                    .type(Integer.valueOf(tmpField.getType()).byteValue())
                                    .label(tmpField.getLabel())
                                    .unit(tmpField.getUnit())
                                    .build())
                    .collect(Collectors.toList());
            dataBuilder.fields(fields);
            List<ValueRow> valueRows = new LinkedList<>();
            for (CollectRep.ValueRow valueRow : storageData.getValuesList()) {
                Map<String, String> labels = new HashMap<>(8);
                List<Value> values = new LinkedList<>();
                for (int i = 0; i < fields.size(); i++) {
                    Field field = fields.get(i);
                    String origin = valueRow.getColumns(i);
                    if (CommonConstants.NULL_VALUE.equals(origin)) {
                        values.add(new Value());
                    } else {
                        values.add(new Value(origin));
                        if (field.getLabel()) {
                            labels.put(field.getName(), origin);
                        }
                    }
                }
                valueRows.add(ValueRow.builder().labels(labels).values(values).build());
            }
            dataBuilder.valueRows(valueRows);
            return ResponseEntity.ok(Message.success(dataBuilder.build()));
        }
    }

    @GetMapping("/api/monitor/{monitorId}/metric/{metricFull}")
    @Operation(summary = "Queries historical data for a specified metric for monitoring", description = "Queries historical data for a specified metric under monitoring")
    public ResponseEntity<Message<MetricsHistoryData>> getMetricHistoryData(
            @Parameter(description = "monitor the task ID", example = "343254354")
            @PathVariable Long monitorId,
            @Parameter(description = "monitor metric full path", example = "linux.cpu.usage")
            @PathVariable() String metricFull,
            @Parameter(description = "label filter, empty by default", example = "disk2")
            @RequestParam(required = false) String label,
            @Parameter(description = "query historical time period, default 6h-6 hours: s-seconds, M-minutes, h-hours, d-days, w-weeks", example = "6h")
            @RequestParam(required = false) String history,
            @Parameter(description = "aggregate data calc. off by default; 4-hour window, query limit >1 week", example = "false")
            @RequestParam(required = false) Boolean interval
    ) {<FILL_FUNCTION_BODY>}
}

        AbstractHistoryDataStorage historyDataStorage = historyDataStorages.stream()
                .filter(AbstractHistoryDataStorage::isServerAvailable).max((o1, o2) -> {
                    if (o1 instanceof HistoryJpaDatabaseDataStorage) {
                        return -1;
                    } else if (o2 instanceof HistoryJpaDatabaseDataStorage) {
                        return 1;
                    } else {
                        return 0;
                    }
                }).orElse(null);
        if (historyDataStorage == null) {
            return ResponseEntity.ok(Message.fail(FAIL_CODE, "time series database not available"));
        }
        String[] names = metricFull.split("\\.");
        if (names.length != METRIC_FULL_LENGTH) {
            throw new IllegalArgumentException("metrics full name: " + metricFull + " is illegal.");
        }
        String app = names[0];
        String metrics = names[1];
        String metric = names[2];
        if (history == null) {
            history = "6h";
        }
        Map<String, List<Value>> instanceValuesMap;
        if (interval == null || !interval) {
            instanceValuesMap = historyDataStorage.getHistoryMetricData(monitorId, app, metrics, metric, label, history);
        } else {
            instanceValuesMap = historyDataStorage.getHistoryIntervalMetricData(monitorId, app, metrics, metric, label, history);
        }
        MetricsHistoryData historyData = MetricsHistoryData.builder()
                .id(monitorId).metrics(metrics).values(instanceValuesMap)
                .field(Field.builder().name(metric).type(CommonConstants.TYPE_NUMBER).build())
                .build();
        return ResponseEntity.ok(Message.success(historyData));
    
<no_super_class>