]> git.basschouten.com Git - openhab-addons.git/blob
764a06a2f658ed771bdb273ac91e55b843afb1a6
[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.bticinosmarther.internal.account;
14
15 import java.io.IOException;
16 import java.util.List;
17
18 import javax.servlet.ServletException;
19 import javax.servlet.http.HttpServlet;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.eclipse.jetty.http.HttpStatus;
26 import org.openhab.binding.bticinosmarther.internal.api.dto.Notification;
27 import org.openhab.binding.bticinosmarther.internal.api.exception.SmartherGatewayException;
28 import org.openhab.binding.bticinosmarther.internal.util.ModelUtil;
29 import org.openhab.binding.bticinosmarther.internal.util.StringUtil;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.google.gson.JsonSyntaxException;
34 import com.google.gson.reflect.TypeToken;
35
36 /**
37  * The {@code SmartherNotificationServlet} class acts as the registered endpoint to receive module status notifications
38  * from the Legrand/Bticino C2C Webhook notification service.
39  *
40  * @author Fabio Possieri - Initial contribution
41  */
42 @NonNullByDefault
43 public class SmartherNotificationServlet extends HttpServlet {
44
45     private static final long serialVersionUID = -2474355132186048438L;
46
47     private static final String CONTENT_TYPE = "application/json;charset=UTF-8";
48     private static final String OK_RESULT_MSG = "{\"result\":0}";
49     private static final String KO_RESULT_MSG = "{\"result\":1}";
50
51     private final Logger logger = LoggerFactory.getLogger(SmartherNotificationServlet.class);
52
53     private final SmartherAccountService accountService;
54
55     /**
56      * Constructs a {@code SmartherNotificationServlet} associated to the given {@link SmartherAccountService} service.
57      *
58      * @param accountService
59      *            the account service to associate to the servlet
60      */
61     public SmartherNotificationServlet(SmartherAccountService accountService) {
62         this.accountService = accountService;
63     }
64
65     @Override
66     protected void doPost(@Nullable HttpServletRequest request, @Nullable HttpServletResponse response)
67             throws ServletException, IOException {
68         if (request != null && response != null) {
69             logger.debug("Notification callback servlet received POST request {}", request.getRequestURI());
70
71             // Handle the received data
72             final String requestBody = StringUtil.readerToString(request.getReader());
73             final String responseBody = dispatchNotifications(requestBody);
74
75             // Build a http 200 (Success) response for the caller
76             response.setContentType(CONTENT_TYPE);
77             response.setStatus(HttpStatus.OK_200);
78             response.getWriter().append(responseBody);
79             response.getWriter().close();
80         } else if (response != null) {
81             // Build a http 400 (Bad Request) error response for the caller
82             response.setContentType(CONTENT_TYPE);
83             response.setStatus(HttpStatus.BAD_REQUEST_400);
84             response.getWriter().close();
85         } else {
86             throw new ServletException("Notification callback with null request/response");
87         }
88     }
89
90     /**
91      * Dispatches all the notifications contained in the received payload to the proper notification handlers.
92      * The response to the notification service is generated based on the different outcomes.
93      *
94      * @param payload
95      *            the received servlet payload to process, may be {@code null}
96      *
97      * @return a string containing the response to the notification service
98      */
99     private String dispatchNotifications(@Nullable String payload) {
100         try {
101             logger.trace("C2C listener received payload: {}", payload);
102             if (!StringUtil.isBlank(payload)) {
103                 List<Notification> notifications = ModelUtil.gsonInstance().fromJson(payload,
104                         new TypeToken<List<Notification>>() {
105                         }.getType());
106
107                 if (notifications != null) {
108                     notifications.forEach(n -> handleSmartherNotification(n));
109                 }
110             }
111             return OK_RESULT_MSG;
112         } catch (JsonSyntaxException e) {
113             logger.warn("C2C payload parsing error: {} ", e.getMessage());
114             return KO_RESULT_MSG;
115         }
116     }
117
118     /**
119      * Dispatches a single notification contained in the received payload to the proper notification handler.
120      *
121      * @param notification
122      *            the notification to dispatch
123      */
124     private void handleSmartherNotification(Notification notification) {
125         try {
126             this.accountService.dispatchNotification(notification);
127         } catch (SmartherGatewayException e) {
128             logger.warn("C2C notification {}: not applied: {}", notification.getId(), e.getMessage());
129         }
130     }
131 }