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.netatmo.internal.servlet;
15 import java.io.IOException;
17 import java.nio.charset.StandardCharsets;
19 import java.util.concurrent.ConcurrentHashMap;
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
23 import javax.ws.rs.HttpMethod;
24 import javax.ws.rs.core.MediaType;
25 import javax.ws.rs.core.UriBuilder;
26 import javax.ws.rs.core.UriBuilderException;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.openhab.binding.netatmo.internal.api.NetatmoException;
30 import org.openhab.binding.netatmo.internal.api.SecurityApi;
31 import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent;
32 import org.openhab.binding.netatmo.internal.deserialization.NADeserializer;
33 import org.openhab.binding.netatmo.internal.handler.ApiBridgeHandler;
34 import org.openhab.binding.netatmo.internal.handler.capability.Capability;
35 import org.osgi.service.http.HttpService;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
40 * HTTP servlet for Netatmo Webhook.
42 * @author Gaƫl L'hopital - Initial contribution
45 public class WebhookServlet extends NetatmoServlet {
46 private static final long serialVersionUID = -354583910860541214L;
48 private final Map<String, Capability> dataListeners = new ConcurrentHashMap<>();
49 private final Logger logger = LoggerFactory.getLogger(WebhookServlet.class);
50 private final SecurityApi securityApi;
51 private final NADeserializer deserializer;
52 private final String webHookUrl;
53 private final String webHookPostfix;
55 private boolean hookSet = false;
57 public WebhookServlet(ApiBridgeHandler handler, HttpService httpService, NADeserializer deserializer,
58 SecurityApi securityApi, String webHookUrl, String webHookPostfix) {
59 super(handler, httpService, "webhook");
60 this.deserializer = deserializer;
61 this.securityApi = securityApi;
62 this.webHookUrl = webHookUrl;
63 this.webHookPostfix = webHookPostfix;
67 public void startListening() {
68 super.startListening();
69 URI uri = UriBuilder.fromUri(webHookUrl).path(path + webHookPostfix).build();
71 logger.info("Setting up WebHook at Netatmo to {}", uri.toString());
72 hookSet = securityApi.addwebhook(uri);
73 } catch (UriBuilderException e) {
74 logger.info("webhookUrl is not a valid URI '{}' : {}", uri, e.getMessage());
75 } catch (NetatmoException e) {
76 logger.info("Error setting webhook : {}", e.getMessage());
81 public void dispose() {
83 logger.info("Releasing WebHook at Netatmo ");
85 securityApi.dropWebhook();
87 } catch (NetatmoException e) {
88 logger.warn("Error releasing webhook : {}", e.getMessage());
95 protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
97 processEvent(new String(req.getInputStream().readAllBytes(), StandardCharsets.UTF_8));
100 private void processEvent(String data) throws IOException {
101 if (!data.isEmpty()) {
102 logger.debug("Event transmitted from restService : {}", data);
104 WebhookEvent event = deserializer.deserialize(WebhookEvent.class, data);
105 notifyListeners(event);
106 } catch (NetatmoException e) {
107 logger.debug("Error deserializing webhook data received : {}. {}", data, e.getMessage());
112 private void replyQuick(HttpServletResponse resp) throws IOException {
113 resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
114 resp.setContentType(MediaType.APPLICATION_JSON);
115 resp.setHeader("Access-Control-Allow-Origin", "*");
116 resp.setHeader("Access-Control-Allow-Methods", HttpMethod.POST);
117 resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
118 resp.setIntHeader("Access-Control-Max-Age", 3600);
119 resp.getWriter().write("");
122 private void notifyListeners(WebhookEvent event) {
123 event.getNAObjectList().forEach(id -> {
124 Capability module = dataListeners.get(id);
125 if (module != null) {
126 module.setNewData(event);
131 public void registerDataListener(String id, Capability capability) {
132 dataListeners.put(id, capability);
135 public void unregisterDataListener(String id) {
136 dataListeners.remove(id);