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.bticinosmarther.internal.account;
15 import java.io.IOException;
16 import java.util.List;
18 import javax.servlet.ServletException;
19 import javax.servlet.http.HttpServlet;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
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;
33 import com.google.gson.JsonSyntaxException;
34 import com.google.gson.reflect.TypeToken;
37 * The {@code SmartherNotificationServlet} class acts as the registered endpoint to receive module status notifications
38 * from the Legrand/Bticino C2C Webhook notification service.
40 * @author Fabio Possieri - Initial contribution
43 public class SmartherNotificationServlet extends HttpServlet {
45 private static final long serialVersionUID = -2474355132186048438L;
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}";
51 private final Logger logger = LoggerFactory.getLogger(SmartherNotificationServlet.class);
53 private final SmartherAccountService accountService;
56 * Constructs a {@code SmartherNotificationServlet} associated to the given {@link SmartherAccountService} service.
58 * @param accountService
59 * the account service to associate to the servlet
61 public SmartherNotificationServlet(SmartherAccountService accountService) {
62 this.accountService = accountService;
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());
71 // Handle the received data
72 final String requestBody = StringUtil.readerToString(request.getReader());
73 final String responseBody = dispatchNotifications(requestBody);
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();
86 throw new ServletException("Notification callback with null request/response");
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.
95 * the received servlet payload to process, may be {@code null}
97 * @return a string containing the response to the notification service
99 private String dispatchNotifications(@Nullable String payload) {
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>>() {
107 if (notifications != null) {
108 notifications.forEach(n -> handleSmartherNotification(n));
111 return OK_RESULT_MSG;
112 } catch (JsonSyntaxException e) {
113 logger.warn("C2C payload parsing error: {} ", e.getMessage());
114 return KO_RESULT_MSG;
119 * Dispatches a single notification contained in the received payload to the proper notification handler.
121 * @param notification
122 * the notification to dispatch
124 private void handleSmartherNotification(Notification notification) {
126 this.accountService.dispatchNotification(notification);
127 } catch (SmartherGatewayException e) {
128 logger.warn("C2C notification {}: not applied: {}", notification.getId(), e.getMessage());