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.heos.internal.json;
15 import java.net.URLDecoder;
16 import java.nio.charset.StandardCharsets;
17 import java.util.Arrays;
18 import java.util.Collections;
20 import java.util.Objects;
21 import java.util.stream.Collectors;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.heos.internal.json.dto.HeosCommandTuple;
26 import org.openhab.binding.heos.internal.json.dto.HeosEvent;
27 import org.openhab.binding.heos.internal.json.dto.HeosEventObject;
28 import org.openhab.binding.heos.internal.json.dto.HeosResponseObject;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
32 import com.google.gson.FieldNamingPolicy;
33 import com.google.gson.Gson;
34 import com.google.gson.GsonBuilder;
37 * Parser used for parsing the responses of JSON cli
39 * @author Martin van Wingerden - Initial contribution
42 public class HeosJsonParser {
43 private final Logger logger = LoggerFactory.getLogger(HeosJsonParser.class);
45 private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
48 public HeosEventObject parseEvent(String jsonBody) {
49 HeosJsonWrapper wrapper = gson.fromJson(jsonBody, HeosJsonWrapper.class);
51 return postProcess(wrapper.heos);
54 private HeosEventObject postProcess(HeosJsonObject heos) {
55 return new HeosEventObject(HeosEvent.valueOfString(heos.command), heos.command, splitQuery(heos.message));
58 public <T> HeosResponseObject<T> parseResponse(String jsonBody, Class<T> clazz) {
59 HeosJsonWrapper wrapper = gson.fromJson(jsonBody, HeosJsonWrapper.class);
60 return postProcess(Objects.requireNonNull(wrapper), clazz);
63 private <T> HeosResponseObject<T> postProcess(HeosJsonWrapper wrapper, Class<T> clazz) {
64 T payload = gson.fromJson(wrapper.payload, clazz);
66 return new HeosResponseObject<>(HeosCommandTuple.valueOf(wrapper.heos.command), wrapper.heos.command,
67 wrapper.heos.result, splitQuery(wrapper.heos.message), payload, wrapper.options);
70 private Map<String, String> splitQuery(@Nullable String url) {
72 return Collections.emptyMap();
75 return Arrays.stream(url.split("&")).map(p -> p.split("=", 2))
76 .collect(Collectors.toMap(v -> decode(v[0]), v -> v.length == 1 ? "" : decode(v[1]), this::merge));
80 * for duplicates we ignore the first one
82 * @param v1 first occurrence
83 * @param v2 second occurrence
84 * @return second occurrence
86 private String merge(String v1, String v2) {
87 logger.debug("Ignoring first occurrence '{}' in favor of '{}'", v1, v2);
91 private static String decode(String encoded) {
92 return URLDecoder.decode(encoded, StandardCharsets.UTF_8);