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.magentatv.internal.network;
15 import static org.openhab.binding.magentatv.internal.MagentaTVBindingConstants.*;
16 import static org.openhab.binding.magentatv.internal.MagentaTVUtil.substringBetween;
18 import java.io.IOException;
19 import java.nio.charset.StandardCharsets;
21 import java.util.Scanner;
23 import javax.servlet.ServletException;
24 import javax.servlet.http.HttpServlet;
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.openhab.binding.magentatv.internal.MagentaTVHandlerFactory;
31 import org.osgi.service.component.annotations.Activate;
32 import org.osgi.service.component.annotations.Component;
33 import org.osgi.service.component.annotations.ConfigurationPolicy;
34 import org.osgi.service.component.annotations.Reference;
35 import org.osgi.service.http.HttpService;
36 import org.osgi.service.http.NamespaceException;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * Main OSGi service and HTTP servlet for MagentaTV NOTIFY.
43 * @author Markus Michels - Initial contribution
46 @Component(service = HttpServlet.class, configurationPolicy = ConfigurationPolicy.OPTIONAL)
47 public class MagentaTVNotifyServlet extends HttpServlet {
48 private static final long serialVersionUID = 2119809008606371618L;
49 private final Logger logger = LoggerFactory.getLogger(MagentaTVNotifyServlet.class);
51 private final MagentaTVHandlerFactory handlerFactory;
54 public MagentaTVNotifyServlet(@Reference MagentaTVHandlerFactory handlerFactory, @Reference HttpService httpService,
55 Map<String, Object> config) {
56 this.handlerFactory = handlerFactory;
58 httpService.registerServlet(PAIRING_NOTIFY_URI, this, null, httpService.createDefaultHttpContext());
59 logger.debug("Servlet started at {}", PAIRING_NOTIFY_URI);
60 if (!handlerFactory.getNotifyServletStatus()) {
61 handlerFactory.setNotifyServletStatus(true);
63 } catch (ServletException | NamespaceException e) {
64 logger.warn("Could not start MagentaTVNotifyServlet: {}", e.getMessage());
69 * Notify servlet handler (will be called by jetty
72 * Format of SOAP message:
76 * <e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0"> <e:property>
77 * <uniqueDeviceID>1C18548DAF7DE9BC231249DB28D2A650</uniqueDeviceID>
78 * </e:property> <e:property> <messageBody>X-pairingCheck:5218C0AA</messageBody>
79 * </e:property> </e:propertyset>
83 * Format of event message: {@code <?xml version="1.0"?>}
87 * <e:propertyset xmlns:e="urn:schemas-upnp-org:event-1-0"> <e:property>
88 * <STB_Mac>AC6FBB61B1E5</STB_Mac> </e:property> <e:property>
89 * <STB_playContent>{"new_play_mode":0,"playBackState":1,&
90 * quot;mediaType":1,"mediaCode":"3682"}</
91 * STB_playContent> </e:property> </e:propertyset>
97 * @throws ServletException
101 protected void service(@Nullable HttpServletRequest request, @Nullable HttpServletResponse response)
102 throws ServletException, IOException {
103 String data = inputStreamToString(request);
105 if ((request == null) || (response == null)) {
108 String ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
109 if (ipAddress == null) {
110 ipAddress = request.getRemoteAddr();
112 String path = request.getRequestURI();
113 logger.trace("Reqeust from {}:{}{} ({}, {})", ipAddress, request.getRemotePort(), path,
114 request.getRemoteHost(), request.getProtocol());
115 if (!path.equalsIgnoreCase(PAIRING_NOTIFY_URI)) {
116 logger.debug("Invalid request received - path = {}", path);
120 if (data.contains(NOTIFY_PAIRING_CODE)) {
121 String deviceId = data.substring(data.indexOf("<uniqueDeviceID>") + "<uniqueDeviceID>".length(),
122 data.indexOf("</uniqueDeviceID>"));
123 String pairingCode = data.substring(data.indexOf(NOTIFY_PAIRING_CODE) + NOTIFY_PAIRING_CODE.length(),
124 data.indexOf("</messageBody>"));
125 logger.debug("Pairing code {} received for deviceID {}", pairingCode, deviceId);
126 if (!handlerFactory.notifyPairingResult(deviceId, ipAddress, pairingCode)) {
127 logger.trace("Pairing data={}", data);
130 if (data.contains("STB_")) {
131 data = data.replace(""", "\"");
132 String stbMac = substringBetween(data, "<STB_Mac>", "</STB_Mac>");
133 String stbEvent = "";
134 if (data.contains("<STB_playContent>")) {
135 stbEvent = substringBetween(data, "<STB_playContent>", "</STB_playContent>");
136 } else if (data.contains("<STB_EitChanged>")) {
137 stbEvent = substringBetween(data, "<STB_EitChanged>", "</STB_EitChanged>");
139 logger.debug("Unknown STB event: {}", data);
141 if (!stbEvent.isEmpty()) {
142 if (!handlerFactory.notifyMREvent(stbMac, stbEvent)) {
143 logger.debug("Event not processed, data={}", data);
148 } catch (RuntimeException e) {
149 logger.debug("Unable to process http request, data={}", data != null ? data : "<empty>");
152 if (response != null) {
153 response.setCharacterEncoding(StandardCharsets.UTF_8.name());
154 response.getWriter().write("");
159 @SuppressWarnings("resource")
160 private String inputStreamToString(@Nullable HttpServletRequest request) throws IOException {
161 if (request == null) {
164 Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
165 return scanner.hasNext() ? scanner.next() : "";