]> git.basschouten.com Git - openhab-addons.git/blob
378081e296062def2e764b92842585b0f775e368
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.io.InputStream;
17 import java.net.URI;
18 import java.nio.charset.StandardCharsets;
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Scanner;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27 import javax.ws.rs.HttpMethod;
28 import javax.ws.rs.core.MediaType;
29 import javax.ws.rs.core.UriBuilder;
30 import javax.ws.rs.core.UriBuilderException;
31
32 import org.eclipse.jdt.annotation.NonNullByDefault;
33 import org.openhab.binding.netatmo.internal.api.NetatmoException;
34 import org.openhab.binding.netatmo.internal.api.SecurityApi;
35 import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent;
36 import org.openhab.binding.netatmo.internal.deserialization.NADeserializer;
37 import org.openhab.binding.netatmo.internal.handler.ApiBridgeHandler;
38 import org.openhab.binding.netatmo.internal.handler.capability.EventCapability;
39 import org.osgi.service.http.HttpService;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * HTTP servlet for Netatmo Webhook.
45  *
46  * @author GaĆ«l L'hopital - Initial contribution
47  */
48 @NonNullByDefault
49 public class WebhookServlet extends NetatmoServlet {
50     private static final long serialVersionUID = -354583910860541214L;
51
52     private final Map<String, EventCapability> dataListeners = new ConcurrentHashMap<>();
53     private final Logger logger = LoggerFactory.getLogger(WebhookServlet.class);
54     private final SecurityApi securityApi;
55     private final NADeserializer deserializer;
56     private final String webHookUrl;
57
58     private boolean hookSet = false;
59
60     public WebhookServlet(ApiBridgeHandler handler, HttpService httpService, NADeserializer deserializer,
61             SecurityApi securityApi, String webHookUrl) {
62         super(handler, httpService, "webhook");
63         this.deserializer = deserializer;
64         this.securityApi = securityApi;
65         this.webHookUrl = webHookUrl;
66     }
67
68     @Override
69     public void startListening() {
70         super.startListening();
71         URI uri = UriBuilder.fromUri(webHookUrl).path(path).build();
72         try {
73             logger.info("Setting up WebHook at Netatmo to {}", uri.toString());
74             hookSet = securityApi.addwebhook(uri);
75         } catch (UriBuilderException e) {
76             logger.info("webhookUrl is not a valid URI '{}' : {}", uri, e.getMessage());
77         } catch (NetatmoException e) {
78             logger.info("Error setting webhook : {}", e.getMessage());
79         }
80     }
81
82     @Override
83     public void dispose() {
84         if (hookSet) {
85             logger.info("Releasing WebHook at Netatmo ");
86             try {
87                 securityApi.dropWebhook();
88                 hookSet = false;
89             } catch (NetatmoException e) {
90                 logger.warn("Error releasing webhook : {}", e.getMessage());
91             }
92         }
93         super.dispose();
94     }
95
96     @Override
97     protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
98         replyQuick(resp);
99         processEvent(inputStreamToString(req.getInputStream()));
100     }
101
102     private void processEvent(String data) throws IOException {
103         if (!data.isEmpty()) {
104             logger.debug("Event transmitted from restService : {}", data);
105             try {
106                 WebhookEvent event = deserializer.deserialize(WebhookEvent.class, data);
107                 List<String> toBeNotified = new ArrayList<>();
108                 toBeNotified.add(event.getCameraId());
109                 toBeNotified.addAll(event.getPersons().keySet());
110                 notifyListeners(toBeNotified, event);
111             } catch (NetatmoException e) {
112                 logger.debug("Error deserializing webhook data received : {}. {}", data, e.getMessage());
113             }
114         }
115     }
116
117     private void replyQuick(HttpServletResponse resp) throws IOException {
118         resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
119         resp.setContentType(MediaType.APPLICATION_JSON);
120         resp.setHeader("Access-Control-Allow-Origin", "*");
121         resp.setHeader("Access-Control-Allow-Methods", HttpMethod.POST);
122         resp.setIntHeader("Access-Control-Max-Age", 3600);
123         resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
124         resp.getWriter().write("");
125     }
126
127     private String inputStreamToString(InputStream is) throws IOException {
128         String value = "";
129         try (Scanner scanner = new Scanner(is)) {
130             scanner.useDelimiter("\\A");
131             value = scanner.hasNext() ? scanner.next() : "";
132         }
133         return value;
134     }
135
136     private void notifyListeners(List<String> tobeNotified, WebhookEvent event) {
137         tobeNotified.forEach(id -> {
138             EventCapability module = dataListeners.get(id);
139             if (module != null) {
140                 module.setNewData(event);
141             }
142         });
143     }
144
145     public void registerDataListener(String id, EventCapability eventCapability) {
146         dataListeners.put(id, eventCapability);
147     }
148
149     public void unregisterDataListener(String id) {
150         dataListeners.remove(id);
151     }
152 }