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.bosesoundtouch.internal;
15 import java.io.IOException;
16 import java.io.StringReader;
17 import java.util.HashMap;
20 import javax.xml.parsers.ParserConfigurationException;
21 import javax.xml.parsers.SAXParser;
22 import javax.xml.parsers.SAXParserFactory;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.binding.bosesoundtouch.internal.handler.BoseSoundTouchHandler;
26 import org.xml.sax.InputSource;
27 import org.xml.sax.SAXException;
28 import org.xml.sax.XMLReader;
31 * The {@link XMLResponseProcessor} class handles the XML mapping
33 * @author Christian Niessner - Initial contribution
34 * @author Thomas Traunbauer - Initial contribution
38 public class XMLResponseProcessor {
39 private BoseSoundTouchHandler handler;
41 private final Map<XMLHandlerState, Map<String, XMLHandlerState>> stateSwitchingMap = new HashMap<>();
43 public XMLResponseProcessor(BoseSoundTouchHandler handler) {
44 this.handler = handler;
48 public void handleMessage(String msg) throws SAXException, IOException, ParserConfigurationException {
49 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
50 parserFactory.setNamespaceAware(true);
51 SAXParser parser = parserFactory.newSAXParser();
52 XMLReader reader = parser.getXMLReader();
53 reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
54 reader.setContentHandler(new XMLResponseHandler(handler, stateSwitchingMap));
55 reader.parse(new InputSource(new StringReader(msg)));
58 // initializes our XML parsing state machine
60 Map<String, XMLHandlerState> msgInitMap = new HashMap<>();
61 stateSwitchingMap.put(XMLHandlerState.INIT, msgInitMap);
62 msgInitMap.put("msg", XMLHandlerState.Msg);
63 msgInitMap.put("SoundTouchSdkInfo", XMLHandlerState.Unprocessed);
64 msgInitMap.put("userActivityUpdate", XMLHandlerState.Unprocessed); // ignored..
66 Map<String, XMLHandlerState> msgBodyMap = new HashMap<>();
67 stateSwitchingMap.put(XMLHandlerState.MsgBody, msgBodyMap);
68 msgBodyMap.put("info", XMLHandlerState.Info);
69 msgBodyMap.put("volume", XMLHandlerState.Volume);
70 msgBodyMap.put("presets", XMLHandlerState.Presets);
71 msgBodyMap.put("key", XMLHandlerState.Unprocessed); // only confirmation of our key presses...
72 msgBodyMap.put("status", XMLHandlerState.Unprocessed); // only confirmation of commands sent to device...
73 msgBodyMap.put("zone", XMLHandlerState.Zone); // only confirmation of our key presses...
74 msgBodyMap.put("bass", XMLHandlerState.Bass);
75 msgBodyMap.put("sources", XMLHandlerState.Sources);
76 msgBodyMap.put("bassCapabilities", XMLHandlerState.BassCapabilities);
77 msgBodyMap.put("group", XMLHandlerState.Group);
79 // info message states
80 Map<String, XMLHandlerState> infoMap = new HashMap<>();
81 stateSwitchingMap.put(XMLHandlerState.Info, infoMap);
82 infoMap.put("components", XMLHandlerState.Info);
83 infoMap.put("component", XMLHandlerState.Info);
84 infoMap.put("name", XMLHandlerState.InfoName);
85 infoMap.put("type", XMLHandlerState.InfoType);
86 infoMap.put("componentCategory", XMLHandlerState.Unprocessed);
87 infoMap.put("softwareVersion", XMLHandlerState.InfoFirmwareVersion);
88 infoMap.put("serialNumber", XMLHandlerState.Unprocessed);
89 infoMap.put("networkInfo", XMLHandlerState.Unprocessed);
90 infoMap.put("margeAccountUUID", XMLHandlerState.Unprocessed);
91 infoMap.put("margeURL", XMLHandlerState.Unprocessed);
92 infoMap.put("moduleType", XMLHandlerState.InfoModuleType);
93 infoMap.put("variant", XMLHandlerState.Unprocessed);
94 infoMap.put("variantMode", XMLHandlerState.Unprocessed);
95 infoMap.put("countryCode", XMLHandlerState.Unprocessed);
96 infoMap.put("regionCode", XMLHandlerState.Unprocessed);
98 Map<String, XMLHandlerState> updatesMap = new HashMap<>();
99 stateSwitchingMap.put(XMLHandlerState.Updates, updatesMap);
100 updatesMap.put("clockDisplayUpdated", XMLHandlerState.Unprocessed); // can we get anything useful of that?
101 updatesMap.put("connectionStateUpdated", XMLHandlerState.UnprocessedNoTextExpected);
102 updatesMap.put("infoUpdated", XMLHandlerState.Unprocessed);
103 updatesMap.put("nowPlayingUpdated", XMLHandlerState.MsgBody);
104 updatesMap.put("nowSelectionUpdated", XMLHandlerState.Unprocessed); // TODO this seems to be quite a useful info
105 // what is currently played..
106 updatesMap.put("recentsUpdated", XMLHandlerState.Unprocessed);
107 updatesMap.put("volumeUpdated", XMLHandlerState.MsgBody);
108 updatesMap.put("zoneUpdated", XMLHandlerState.ZoneUpdated); // just notifies but dosn't provide details
109 updatesMap.put("bassUpdated", XMLHandlerState.BassUpdated);
110 updatesMap.put("presetsUpdated", XMLHandlerState.MsgBody);
111 updatesMap.put("groupUpdated", XMLHandlerState.MsgBody);
113 Map<String, XMLHandlerState> volume = new HashMap<>();
114 stateSwitchingMap.put(XMLHandlerState.Volume, volume);
115 volume.put("targetvolume", XMLHandlerState.VolumeTarget);
116 volume.put("actualvolume", XMLHandlerState.VolumeActual);
117 volume.put("muteenabled", XMLHandlerState.VolumeMuteEnabled);
119 Map<String, XMLHandlerState> nowPlayingMap = new HashMap<>();
120 stateSwitchingMap.put(XMLHandlerState.NowPlaying, nowPlayingMap);
121 nowPlayingMap.put("album", XMLHandlerState.NowPlayingAlbum);
122 nowPlayingMap.put("art", XMLHandlerState.NowPlayingArt);
123 nowPlayingMap.put("artist", XMLHandlerState.NowPlayingArtist);
124 nowPlayingMap.put("ContentItem", XMLHandlerState.ContentItem);
125 nowPlayingMap.put("description", XMLHandlerState.NowPlayingDescription);
126 nowPlayingMap.put("playStatus", XMLHandlerState.NowPlayingPlayStatus);
127 nowPlayingMap.put("rateEnabled", XMLHandlerState.NowPlayingRateEnabled);
128 nowPlayingMap.put("skipEnabled", XMLHandlerState.NowPlayingSkipEnabled);
129 nowPlayingMap.put("skipPreviousEnabled", XMLHandlerState.NowPlayingSkipPreviousEnabled);
130 nowPlayingMap.put("stationLocation", XMLHandlerState.NowPlayingStationLocation);
131 nowPlayingMap.put("stationName", XMLHandlerState.NowPlayingStationName);
132 nowPlayingMap.put("track", XMLHandlerState.NowPlayingTrack);
133 nowPlayingMap.put("connectionStatusInfo", XMLHandlerState.Unprocessed); // TODO active when Source==Bluetooth
134 // TODO active when Source==Pandora and maybe also other sources - seems to be rating related
135 nowPlayingMap.put("time", XMLHandlerState.Unprocessed);
136 nowPlayingMap.put("rating", XMLHandlerState.Unprocessed);
137 nowPlayingMap.put("rateEnabled", XMLHandlerState.Unprocessed);
139 // ContentItem specifies a resource (that also could be bookmarked in a preset)
140 Map<String, XMLHandlerState> contentItemMap = new HashMap<>();
141 stateSwitchingMap.put(XMLHandlerState.ContentItem, contentItemMap);
142 contentItemMap.put("itemName", XMLHandlerState.ContentItemItemName);
143 contentItemMap.put("containerArt", XMLHandlerState.ContentItemContainerArt);
145 Map<String, XMLHandlerState> presetMap = new HashMap<>();
146 stateSwitchingMap.put(XMLHandlerState.Preset, presetMap);
147 presetMap.put("ContentItem", XMLHandlerState.ContentItem);
149 Map<String, XMLHandlerState> zoneMap = new HashMap<>();
150 stateSwitchingMap.put(XMLHandlerState.Zone, zoneMap);
151 zoneMap.put("member", XMLHandlerState.ZoneMember);
153 Map<String, XMLHandlerState> bassMap = new HashMap<>();
154 stateSwitchingMap.put(XMLHandlerState.Bass, bassMap);
155 bassMap.put("targetbass", XMLHandlerState.BassTarget);
156 bassMap.put("actualbass", XMLHandlerState.BassActual);
158 Map<String, XMLHandlerState> sourceMap = new HashMap<>();
159 stateSwitchingMap.put(XMLHandlerState.Sources, sourceMap);
161 Map<String, XMLHandlerState> bassCapabilitiesMap = new HashMap<>();
162 stateSwitchingMap.put(XMLHandlerState.BassCapabilities, bassCapabilitiesMap);
163 bassCapabilitiesMap.put("bassAvailable", XMLHandlerState.BassAvailable);
164 bassCapabilitiesMap.put("bassMin", XMLHandlerState.BassMin);
165 bassCapabilitiesMap.put("bassMax", XMLHandlerState.BassMax);
166 bassCapabilitiesMap.put("bassDefault", XMLHandlerState.BassDefault);
168 Map<String, XMLHandlerState> groupsMap = new HashMap<>();
169 stateSwitchingMap.put(XMLHandlerState.Group, groupsMap);
170 groupsMap.put("name", XMLHandlerState.GroupName);
171 groupsMap.put("masterDeviceId", XMLHandlerState.MasterDeviceId);
172 groupsMap.put("roles", XMLHandlerState.Unprocessed);
173 groupsMap.put("senderIPAddress", XMLHandlerState.Unprocessed);
174 groupsMap.put("status", XMLHandlerState.Unprocessed);
175 groupsMap.put("roles", XMLHandlerState.Unprocessed);
176 groupsMap.put("groupRole", XMLHandlerState.Unprocessed);
177 groupsMap.put("deviceId", XMLHandlerState.DeviceId);
178 groupsMap.put("role", XMLHandlerState.Unprocessed);
179 groupsMap.put("ipAddress", XMLHandlerState.DeviceIp);