2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.networkupstools.internal.nut;
15 import java.util.HashMap;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
25 * Util class to process NUT List results.
27 * @author Hilbrand Bouwkamp - Initial contribution
30 final class NutResponseReader {
32 private static final String BEGIN_LIST = "BEGIN LIST %s";
33 private static final String END_LIST = "END LIST %s";
34 private static final Pattern LIST_ROW_RESPONSE_PATTERN = Pattern.compile("([^\"]+)\"(.+)\"$");
35 private static final Pattern GET_VAR_RESPONSE_PATTERN = Pattern.compile("VAR ([^\\s]+) ([^\"]+)\"(.+)\"$");
37 private final Logger logger = LoggerFactory.getLogger(NutResponseReader.class);
40 * Parses a NUT returned VAR.
42 * @param ups The ups the variable is for
43 * @param nut The name of the variable
44 * @param reader The reader containing the data
45 * @return variable value for given nut variable name
46 * @throws NutException Exception thrown in case of read errors
48 public String parseVariable(final String ups, final String nut, final NutSupplier<String> reader)
50 final String line = reader.get();
53 throw new NutException(
54 String.format("Variable '%s' for ups '%s' could not be read because nothing received", nut, ups));
56 logger.trace("Line read:{}", line);
57 final Matcher matcher = GET_VAR_RESPONSE_PATTERN.matcher(line);
59 if (matcher.find() && matcher.groupCount() == 3) {
60 final String matchedUps = matcher.group(1).trim();
61 final String matchedNut = matcher.group(2).trim();
62 final String value = stripVariable(matcher.group(3));
64 if (!ups.equals(matchedUps)) {
65 throw new NutException(
66 String.format("Returned value '%s' didn't match expected ups '%s'", matchedUps, ups));
68 if (!nut.equals(matchedNut)) {
69 throw new NutException(
70 String.format("Returned value '%s' didn't match expected nut '%s'", matchedNut, nut));
74 throw new NutException(String.format("Variable '%s' for ups '%s' could not be read: %s", nut, ups, line));
78 * Parses a NUT returned LIST.
80 * @param type nut data type to expect in the data
81 * @param reader The reader containing the data
82 * @param variables The map to store the read nut variables
83 * @return Map of variable name and variable value pairs
84 * @throws NutException Exception thrown in case of read errors
86 public Map<String, String> parseList(final String type, final NutSupplier<String> reader) throws NutException {
87 final Map<String, String> variables = new HashMap<>();
88 logger.trace("Reading {}", type);
89 validateBegin(type, reader);
90 final int stripBeginLength = type.length() + 1;
91 final String endString = String.format(END_LIST, type);
93 boolean endFound = false;
98 throw new NutException("Unexpected end of data while reading " + type);
100 logger.trace("Line read:{}", line);
101 endFound = endString.equals(line);
103 addRow(variables, line, stripBeginLength);
106 if (logger.isTraceEnabled()) {
107 logger.trace("List '{}' read. {} variables read", type, variables.size());
112 private void validateBegin(final String type, final NutSupplier<String> reader) throws NutException {
113 final String beginString = String.format(BEGIN_LIST, type);
118 logger.trace("Line read:{}", line);
120 throw new NutException("Could not find the begin string pattern in the data while reading " + type);
122 } while (!beginString.equals(line));
123 logger.trace("Begin of list '{}' found", type);
126 private void addRow(final Map<String, String> map, final String row, final int offset) {
127 final String substring = row.substring(offset);
128 final Matcher matcher = LIST_ROW_RESPONSE_PATTERN.matcher(substring);
130 if (matcher.find() && matcher.groupCount() == 2) {
131 final String nut = matcher.group(1).trim();
132 final String value = stripVariable(matcher.group(2));
135 logger.trace("Read nut variable '{}':{}", nut, value);
137 logger.debug("Unrecognized nut results: {}", row);
141 private String stripVariable(final String rawVariable) {
142 return rawVariable.replaceAll("\\\\\"", "\"").replaceAll("\\\\\\\\", "\\\\").trim();