| | |
| | | import com.core.annotations.ManagerAuth; |
| | | import com.core.common.Cools; |
| | | import com.core.common.R; |
| | | import com.zy.asrs.entity.BasDevp; |
| | | import com.zy.asrs.entity.DeviceDataLog; |
| | | import com.zy.asrs.service.BasDevpService; |
| | | import com.zy.common.web.BaseController; |
| | | import com.zy.core.enums.SlaveType; |
| | | import com.zy.core.model.StationObjModel; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.stream.Collectors; |
| | | import java.util.stream.Stream; |
| | | import java.util.zip.ZipEntry; |
| | | import java.util.zip.ZipOutputStream; |
| | | |
| | | @Slf4j |
| | | @RestController |
| | |
| | | DEVICE_TYPE_LABELS.put("Devp", "输送设备"); |
| | | } |
| | | |
| | | @Autowired |
| | | private BasDevpService basDevpService; |
| | | |
| | | @Value("${deviceLogStorage.loggingPath}") |
| | | private String loggingPath; |
| | | |
| | |
| | | private static class FileNameInfo { |
| | | String type; |
| | | String deviceNo; |
| | | String stationId; |
| | | String day; |
| | | int index; |
| | | } |
| | |
| | | String type; |
| | | String typeLabel; |
| | | String deviceNo; |
| | | String stationId; |
| | | List<String> stationIds; |
| | | int fileCount; |
| | | Long firstTime; |
| | | Long lastTime; |
| | |
| | | if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | List<Path> files = Files.list(dayDir) |
| | | .filter(p -> !Files.isDirectory(p) && p.getFileName().toString().endsWith(".log")) |
| | | .collect(Collectors.toList()); |
| | | List<Path> files = listDayLogFiles(dayDir); |
| | | Map<String, Map<String, Object>> deviceMap = new HashMap<>(); |
| | | for (Path p : files) { |
| | | String name = p.getFileName().toString(); |
| | | String[] parts = name.split("_"); |
| | | if (parts.length < 4) { |
| | | FileNameInfo info = parseFileName(p.getFileName().toString()); |
| | | if (info == null || !day.equals(info.day)) { |
| | | continue; |
| | | } |
| | | String deviceNo = parts[1]; |
| | | String type = parts[0]; |
| | | Map<String, Object> info = deviceMap.computeIfAbsent(deviceNo, k -> { |
| | | String deviceKey = buildDeviceKey(info.type, info.deviceNo, info.stationId); |
| | | Map<String, Object> infoMap = deviceMap.computeIfAbsent(deviceKey, k -> { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("deviceNo", deviceNo); |
| | | map.put("deviceNo", info.deviceNo); |
| | | map.put("stationId", info.stationId); |
| | | map.put("types", new HashSet<String>()); |
| | | map.put("fileCount", 0); |
| | | return map; |
| | | }); |
| | | ((Set<String>) info.get("types")).add(type); |
| | | info.put("fileCount", ((Integer) info.get("fileCount")) + 1); |
| | | ((Set<String>) infoMap.get("types")).add(info.type); |
| | | infoMap.put("fileCount", ((Integer) infoMap.get("fileCount")) + 1); |
| | | } |
| | | List<Map<String, Object>> res = deviceMap.values().stream().map(m -> { |
| | | Map<String, Object> x = new HashMap<>(); |
| | | x.put("deviceNo", m.get("deviceNo")); |
| | | x.put("stationId", m.get("stationId")); |
| | | x.put("types", ((Set<String>) m.get("types")).stream().collect(Collectors.toList())); |
| | | x.put("fileCount", m.get("fileCount")); |
| | | return x; |
| | |
| | | } |
| | | |
| | | Map<String, DeviceAggregate> aggregateMap = new LinkedHashMap<>(); |
| | | try (Stream<Path> stream = Files.list(dayDir)) { |
| | | List<Path> files = stream |
| | | .filter(p -> !Files.isDirectory(p) && p.getFileName().toString().endsWith(".log")) |
| | | .collect(Collectors.toList()); |
| | | List<Path> files = listDayLogFiles(dayDir); |
| | | for (Path file : files) { |
| | | FileNameInfo info = parseFileName(file.getFileName().toString()); |
| | | if (info == null || !dayClean.equals(info.day) || !DEVICE_TYPE_LABELS.containsKey(info.type)) { |
| | | continue; |
| | | } |
| | | String key = info.type + ":" + info.deviceNo; |
| | | String key = buildDeviceKey(info.type, info.deviceNo, info.stationId); |
| | | DeviceAggregate aggregate = aggregateMap.computeIfAbsent(key, k -> { |
| | | DeviceAggregate x = new DeviceAggregate(); |
| | | x.type = info.type; |
| | | x.typeLabel = DEVICE_TYPE_LABELS.get(info.type); |
| | | x.deviceNo = info.deviceNo; |
| | | x.stationId = info.stationId; |
| | | return x; |
| | | }); |
| | | aggregate.fileCount += 1; |
| | |
| | | aggregate.lastFile = file; |
| | | } |
| | | } |
| | | } |
| | | for (DeviceAggregate aggregate : aggregateMap.values()) { |
| | | if (aggregate.firstFile != null) { |
| | | FileTimeRange firstRange = readFileTimeRange(aggregate.firstFile); |
| | |
| | | aggregate.lastTime = lastRange.endTime != null ? lastRange.endTime : lastRange.startTime; |
| | | } |
| | | } |
| | | enrichDevpStationIds(aggregateMap.values()); |
| | | return R.ok(buildSummaryResponse(aggregateMap.values())); |
| | | } catch (Exception e) { |
| | | log.error("读取设备日志摘要失败", e); |
| | |
| | | @ManagerAuth |
| | | public R timeline(@PathVariable("day") String day, |
| | | @RequestParam("type") String type, |
| | | @RequestParam("deviceNo") String deviceNo) { |
| | | @RequestParam("deviceNo") String deviceNo, |
| | | @RequestParam(value = "stationId", required = false) String stationId) { |
| | | try { |
| | | String dayClean = normalizeDay(day); |
| | | if (dayClean == null) { |
| | |
| | | if (deviceNo == null || !deviceNo.chars().allMatch(Character::isDigit)) { |
| | | return R.error("设备编号错误"); |
| | | } |
| | | if (isDevpType(type) && (stationId == null || !stationId.chars().allMatch(Character::isDigit))) { |
| | | return R.error("站点编号错误"); |
| | | } |
| | | Path dayDir = Paths.get(loggingPath, dayClean); |
| | | if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | return R.error("未找到日志文件"); |
| | | } |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo); |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo, stationId); |
| | | if (files.isEmpty()) { |
| | | return R.error("未找到日志文件"); |
| | | } |
| | |
| | | result.put("type", type); |
| | | result.put("typeLabel", DEVICE_TYPE_LABELS.getOrDefault(type, type)); |
| | | result.put("deviceNo", deviceNo); |
| | | result.put("stationId", stationId); |
| | | result.put("startTime", startTime); |
| | | result.put("endTime", endTime); |
| | | result.put("totalFiles", files.size()); |
| | |
| | | public R preview(@PathVariable("day") String day, |
| | | @RequestParam("type") String type, |
| | | @RequestParam("deviceNo") String deviceNo, |
| | | @RequestParam(value = "stationId", required = false) String stationId, |
| | | @RequestParam(value = "offset", required = false) Integer offset, |
| | | @RequestParam(value = "limit", required = false) Integer limit) { |
| | | try { |
| | |
| | | if (deviceNo == null || !deviceNo.chars().allMatch(Character::isDigit)) { |
| | | return R.error("设备编号错误"); |
| | | } |
| | | if (isDevpType(type) && (stationId == null || !stationId.chars().allMatch(Character::isDigit))) { |
| | | return R.error("站点编号错误"); |
| | | } |
| | | Path dayDir = Paths.get(loggingPath, dayClean); |
| | | if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | String prefix = type + "_" + deviceNo + "_" + dayClean + "_"; |
| | | List<Path> files = Files.list(dayDir) |
| | | .filter(p -> { |
| | | String name = p.getFileName().toString(); |
| | | return name.endsWith(".log") && name.startsWith(prefix); |
| | | }).collect(Collectors.toList()); |
| | | |
| | | files.sort(Comparator.comparingInt(p -> { |
| | | String n = p.getFileName().toString(); |
| | | try { |
| | | String suf = n.substring(prefix.length(), n.length() - 4); |
| | | return Integer.parseInt(suf); |
| | | } catch (Exception e) { |
| | | return Integer.MAX_VALUE; |
| | | } |
| | | })); |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo, stationId); |
| | | |
| | | int from = offset == null || offset < 0 ? 0 : offset; |
| | | int max = limit == null || limit <= 0 ? 5 : limit; // 默认读取5个文件 |
| | | if (max > 10) max = 10; // 限制最大文件数,防止超时 |
| | | int max = limit == null || limit <= 0 ? 5 : limit; |
| | | if (max > 10) max = 10; |
| | | int to = Math.min(files.size(), from + max); |
| | | |
| | | if (from >= files.size()) { |
| | |
| | | DeviceDataLog logItem = JSON.parseObject(line, DeviceDataLog.class); |
| | | resultLogs.add(logItem); |
| | | } catch (Exception e) { |
| | | // 忽略解析错误 |
| | | } |
| | | } |
| | | }); |
| | |
| | | log.error("读取日志文件失败: " + f, e); |
| | | } |
| | | } |
| | | // 按时间排序 |
| | | resultLogs.sort(Comparator.comparing(DeviceDataLog::getCreateTime, Comparator.nullsLast(Date::compareTo))); |
| | | |
| | | return R.ok(resultLogs); |
| | |
| | | public R seek(@PathVariable("day") String day, |
| | | @RequestParam("type") String type, |
| | | @RequestParam("deviceNo") String deviceNo, |
| | | @RequestParam(value = "stationId", required = false) String stationId, |
| | | @RequestParam("timestamp") Long timestamp) { |
| | | try { |
| | | String dayClean = day == null ? null : day.replaceAll("\\D", ""); |
| | |
| | | if (deviceNo == null || !deviceNo.chars().allMatch(Character::isDigit)) { |
| | | return R.error("设备编号错误"); |
| | | } |
| | | if (isDevpType(type) && (stationId == null || !stationId.chars().allMatch(Character::isDigit))) { |
| | | return R.error("站点编号错误"); |
| | | } |
| | | Path dayDir = Paths.get(loggingPath, dayClean); |
| | | if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | return R.error("未找到日志文件"); |
| | | } |
| | | |
| | | String prefix = type + "_" + deviceNo + "_" + dayClean + "_"; |
| | | List<Path> files = Files.list(dayDir) |
| | | .filter(p -> { |
| | | String name = p.getFileName().toString(); |
| | | return name.endsWith(".log") && name.startsWith(prefix); |
| | | }).collect(Collectors.toList()); |
| | | |
| | | files.sort(Comparator.comparingInt(p -> { |
| | | String n = p.getFileName().toString(); |
| | | try { |
| | | String suf = n.substring(prefix.length(), n.length() - 4); |
| | | return Integer.parseInt(suf); |
| | | } catch (Exception e) { |
| | | return Integer.MAX_VALUE; |
| | | } |
| | | })); |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo, stationId); |
| | | |
| | | if (files.isEmpty()) { |
| | | return R.error("未找到日志文件"); |
| | | } |
| | | |
| | | // Binary search for the file containing the timestamp |
| | | // We want to find the LAST file that has startTime <= targetTime. |
| | | // Because files are sequential: [t0, t1), [t1, t2), ... |
| | | // If we find file[i].startTime <= target < file[i+1].startTime, then target is in file[i]. |
| | | |
| | | int low = 0; |
| | | int high = files.size() - 1; |
| | |
| | | while (low <= high) { |
| | | int mid = (low + high) >>> 1; |
| | | Path midFile = files.get(mid); |
| | | |
| | | // Read start time of this file |
| | | Long midStart = getFileStartTime(midFile); |
| | | if (midStart == null) { |
| | | low = mid + 1; |
| | |
| | | } |
| | | |
| | | if (midStart <= timestamp) { |
| | | // This file starts before or at target. It COULD be the one. |
| | | // But maybe a later file also starts before target? |
| | | foundIndex = mid; |
| | | low = mid + 1; // Try to find a later start time |
| | | low = mid + 1; |
| | | } else { |
| | | // This file starts AFTER target. So target must be in an earlier file. |
| | | high = mid - 1; |
| | | } |
| | | } |
| | |
| | | foundIndex = 0; |
| | | } |
| | | |
| | | // Return the file index (offset) |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("offset", foundIndex); |
| | | return R.ok(result); |
| | |
| | | response.setStatus(400); |
| | | return; |
| | | } |
| | | String stationId = request.getParameter("stationId"); |
| | | if (isDevpType(type) && (stationId == null || !stationId.chars().allMatch(Character::isDigit))) { |
| | | response.setStatus(400); |
| | | return; |
| | | } |
| | | Path dayDir = Paths.get(loggingPath, dayClean); |
| | | if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | response.setStatus(404); |
| | | return; |
| | | } |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo); |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo, stationId); |
| | | files = sliceDownloadFiles(files, offset, limit); |
| | | if (files.isEmpty()) { |
| | | response.setStatus(404); |
| | |
| | | response.setHeader("X-Total-Size", String.valueOf(totalRawSize)); |
| | | response.setHeader("X-File-Count", String.valueOf(files.size())); |
| | | response.setHeader("X-Progress-Id", id); |
| | | try (java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(response.getOutputStream())) { |
| | | try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { |
| | | for (Path f : files) { |
| | | java.util.zip.ZipEntry entry = new java.util.zip.ZipEntry(f.getFileName().toString()); |
| | | ZipEntry entry = new ZipEntry(f.getFileName().toString()); |
| | | zos.putNextEntry(entry); |
| | | Files.copy(f, zos); |
| | | zos.closeEntry(); |
| | |
| | | if (Cools.isEmpty(deviceNo) || !deviceNo.chars().allMatch(Character::isDigit)) { |
| | | return R.error("设备编号错误"); |
| | | } |
| | | String stationId = param.getString("stationId"); |
| | | if (isDevpType(type) && (Cools.isEmpty(stationId) || !stationId.chars().allMatch(Character::isDigit))) { |
| | | return R.error("站点编号错误"); |
| | | } |
| | | Path dayDir = Paths.get(loggingPath, dayClean); |
| | | if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | return R.error("当日目录不存在"); |
| | | } |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo); |
| | | List<Path> files = findDeviceFiles(dayDir, dayClean, type, deviceNo, stationId); |
| | | if ((offset != null && offset >= files.size())) { |
| | | return R.error("起始序号超出范围"); |
| | | } |
| | |
| | | x.put("type", item.type); |
| | | x.put("typeLabel", item.typeLabel); |
| | | x.put("deviceNo", item.deviceNo); |
| | | x.put("stationId", item.stationId); |
| | | x.put("fileCount", item.fileCount); |
| | | x.put("firstTime", item.firstTime); |
| | | x.put("lastTime", item.lastTime); |
| | | x.put("stationIds", item.stationIds == null ? Collections.emptyList() : item.stationIds); |
| | | return x; |
| | | }).collect(Collectors.toList())); |
| | | groups.add(group); |
| | |
| | | return result; |
| | | } |
| | | |
| | | private void enrichDevpStationIds(Collection<DeviceAggregate> aggregates) { |
| | | if (aggregates == null || aggregates.isEmpty() || basDevpService == null) { |
| | | return; |
| | | } |
| | | List<DeviceAggregate> devpAggregates = aggregates.stream() |
| | | .filter(item -> item != null && isDevpType(item.type) && Cools.isEmpty(item.stationId) && !Cools.isEmpty(item.deviceNo)) |
| | | .collect(Collectors.toList()); |
| | | if (devpAggregates.isEmpty()) { |
| | | return; |
| | | } |
| | | List<Integer> devpNos = devpAggregates.stream() |
| | | .map(item -> parseInteger(item.deviceNo)) |
| | | .filter(Objects::nonNull) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | if (devpNos.isEmpty()) { |
| | | return; |
| | | } |
| | | Map<Integer, List<String>> stationIdsByDevpNo = basDevpService.listByIds(devpNos).stream() |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toMap(BasDevp::getDevpNo, this::extractStationIds, (left, right) -> left)); |
| | | for (DeviceAggregate aggregate : devpAggregates) { |
| | | Integer devpNo = parseInteger(aggregate.deviceNo); |
| | | if (devpNo != null) { |
| | | aggregate.stationIds = stationIdsByDevpNo.getOrDefault(devpNo, Collections.emptyList()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private List<String> extractStationIds(BasDevp basDevp) { |
| | | if (basDevp == null) { |
| | | return Collections.emptyList(); |
| | | } |
| | | return basDevp.getStationList$().stream() |
| | | .map(StationObjModel::getStationId) |
| | | .filter(Objects::nonNull) |
| | | .map(String::valueOf) |
| | | .distinct() |
| | | .sorted(Comparator.comparingInt(this::parseDeviceNo)) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | private Integer parseInteger(String value) { |
| | | try { |
| | | return Integer.parseInt(String.valueOf(value)); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private String normalizeDay(String day) { |
| | | String dayClean = day == null ? null : day.replaceAll("\\D", ""); |
| | | if (dayClean == null || dayClean.length() != 8 || !dayClean.chars().allMatch(Character::isDigit)) { |
| | |
| | | return dayClean; |
| | | } |
| | | |
| | | private List<Path> findDeviceFiles(Path dayDir, String dayClean, String type, String deviceNo) throws Exception { |
| | | String prefix = type + "_" + deviceNo + "_" + dayClean + "_"; |
| | | private List<Path> findDeviceFiles(Path dayDir, String dayClean, String type, String deviceNo, String stationId) throws Exception { |
| | | FileNameInfo target = new FileNameInfo(); |
| | | target.type = type; |
| | | target.deviceNo = deviceNo; |
| | | target.stationId = stationId; |
| | | target.day = dayClean; |
| | | Path deviceDir = resolveDeviceDir(dayDir, type, deviceNo); |
| | | if (deviceDir == null || !Files.exists(deviceDir) || !Files.isDirectory(deviceDir)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<Path> files; |
| | | try (Stream<Path> stream = Files.list(dayDir)) { |
| | | try (Stream<Path> stream = Files.list(deviceDir)) { |
| | | files = stream |
| | | .filter(p -> { |
| | | String name = p.getFileName().toString(); |
| | | return name.endsWith(".log") && name.startsWith(prefix); |
| | | }) |
| | | .filter(p -> !Files.isDirectory(p) && matchesFileInfo(parseFileName(p.getFileName().toString()), target)) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | files.sort(Comparator.comparingInt(p -> { |
| | | String n = p.getFileName().toString(); |
| | | try { |
| | | String suf = n.substring(prefix.length(), n.length() - 4); |
| | | return Integer.parseInt(suf); |
| | | } catch (Exception e) { |
| | | return Integer.MAX_VALUE; |
| | | } |
| | | FileNameInfo info = parseFileName(p.getFileName().toString()); |
| | | return info == null ? Integer.MAX_VALUE : info.index; |
| | | })); |
| | | return files; |
| | | } |
| | | |
| | | private List<Path> listDayLogFiles(Path dayDir) throws Exception { |
| | | if (dayDir == null || !Files.exists(dayDir) || !Files.isDirectory(dayDir)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<Path> files = new ArrayList<>(); |
| | | try (Stream<Path> typeStream = Files.list(dayDir)) { |
| | | List<Path> typeDirs = typeStream.filter(Files::isDirectory).collect(Collectors.toList()); |
| | | for (Path typeDir : typeDirs) { |
| | | try (Stream<Path> deviceStream = Files.list(typeDir)) { |
| | | List<Path> deviceDirs = deviceStream.filter(Files::isDirectory).collect(Collectors.toList()); |
| | | for (Path deviceDir : deviceDirs) { |
| | | try (Stream<Path> fileStream = Files.list(deviceDir)) { |
| | | fileStream |
| | | .filter(p -> !Files.isDirectory(p) && p.getFileName().toString().endsWith(".log")) |
| | | .forEach(files::add); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return files; |
| | | } |
| | | |
| | | private Path resolveDeviceDir(Path dayDir, String type, String deviceNo) { |
| | | if (dayDir == null || Cools.isEmpty(type) || Cools.isEmpty(deviceNo)) { |
| | | return null; |
| | | } |
| | | return dayDir.resolve(type).resolve(deviceNo); |
| | | } |
| | | |
| | | private List<Path> sliceDownloadFiles(List<Path> files, Integer offset, Integer limit) { |
| | |
| | | if (fileName == null || !fileName.endsWith(".log")) { |
| | | return null; |
| | | } |
| | | String[] parts = fileName.split("_", 4); |
| | | String fileNameNoExt = fileName.substring(0, fileName.length() - 4); |
| | | String[] parts = fileNameNoExt.split("_"); |
| | | if (parts.length < 4) { |
| | | return null; |
| | | } |
| | | FileNameInfo info = new FileNameInfo(); |
| | | info.type = parts[0]; |
| | | info.deviceNo = parts[1]; |
| | | info.day = parts[2]; |
| | | if (isDevpType(info.type)) { |
| | | if (parts.length != 6 || !"station".equals(parts[2])) { |
| | | return null; |
| | | } |
| | | info.stationId = parts[3]; |
| | | info.day = parts[4]; |
| | | try { |
| | | info.index = Integer.parseInt(parts[3].replace(".log", "")); |
| | | info.index = Integer.parseInt(parts[5]); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | return info; |
| | | } |
| | | if (parts.length != 4) { |
| | | return null; |
| | | } |
| | | info.day = parts[2]; |
| | | try { |
| | | info.index = Integer.parseInt(parts[3]); |
| | | } catch (Exception e) { |
| | | return null; |
| | | } |
| | | return info; |
| | | } |
| | | |
| | | private String buildDeviceKey(String type, String deviceNo, String stationId) { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append(String.valueOf(type)).append(":").append(String.valueOf(deviceNo)); |
| | | if (isDevpType(type)) { |
| | | builder.append(":").append(String.valueOf(stationId)); |
| | | } |
| | | return builder.toString(); |
| | | } |
| | | |
| | | private boolean matchesFileInfo(FileNameInfo actual, FileNameInfo target) { |
| | | if (actual == null || target == null) { |
| | | return false; |
| | | } |
| | | if (!Objects.equals(actual.type, target.type)) { |
| | | return false; |
| | | } |
| | | if (!Objects.equals(actual.deviceNo, target.deviceNo)) { |
| | | return false; |
| | | } |
| | | if (!Objects.equals(actual.day, target.day)) { |
| | | return false; |
| | | } |
| | | if (isDevpType(actual.type)) { |
| | | return Objects.equals(actual.stationId, target.stationId); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | private boolean isDevpType(String type) { |
| | | return SlaveType.Devp.name().equals(type); |
| | | } |
| | | |
| | | private int parseDeviceNo(String deviceNo) { |
| | | try { |