]> git.basschouten.com Git - openhab-addons.git/blob
1fe864e16985b727b3662e10034442730d6db2a5
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.netatmo.internal.servlet;
14
15 import java.io.IOException;
16 import java.net.URI;
17 import java.nio.charset.StandardCharsets;
18 import java.util.Map;
19 import java.util.concurrent.ConcurrentHashMap;
20
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;
27
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;
38
39 /**
40  * HTTP servlet for Netatmo Webhook.
41  *
42  * @author GaĆ«l L'hopital - Initial contribution
43  */
44 @NonNullByDefault
45 public class WebhookServlet extends NetatmoServlet {
46     private static final long serialVersionUID = -354583910860541214L;
47
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;
54
55     private boolean hookSet = false;
56
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;
64     }
65
66     @Override
67     public void startListening() {
68         super.startListening();
69         URI uri = UriBuilder.fromUri(webHookUrl).path(path + webHookPostfix).build();
70         try {
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());
77         }
78     }
79
80     @Override
81     public void dispose() {
82         if (hookSet) {
83             logger.info("Releasing WebHook at Netatmo ");
84             try {
85                 securityApi.dropWebhook();
86                 hookSet = false;
87             } catch (NetatmoException e) {
88                 logger.warn("Error releasing webhook : {}", e.getMessage());
89             }
90         }
91         super.dispose();
92     }
93
94     @Override
95     protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
96         replyQuick(resp);
97         processEvent(new String(req.getInputStream().readAllBytes(), StandardCharsets.UTF_8));
98     }
99
100     private void processEvent(String data) throws IOException {
101         if (!data.isEmpty()) {
102             logger.debug("Event transmitted from restService : {}", data);
103             try {
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());
108             }
109         }
110     }
111
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("");
120     }
121
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);
127             }
128         });
129     }
130
131     public void registerDataListener(String id, Capability capability) {
132         dataListeners.put(id, capability);
133     }
134
135     public void unregisterDataListener(String id) {
136         dataListeners.remove(id);
137     }
138 }