2 * Copyright (c) 2010-2024 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.mielecloud.internal.config.servlet;
15 import java.io.IOException;
16 import java.util.Locale;
17 import java.util.Optional;
19 import java.util.stream.Collectors;
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.openhab.binding.mielecloud.internal.config.ThingsTemplateGenerator;
26 import org.openhab.binding.mielecloud.internal.webservice.language.LanguageProvider;
27 import org.openhab.core.thing.ThingUID;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * Servlet showing the success page.
34 * @author Björn Lange - Initial Contribution
37 public class SuccessServlet extends AbstractShowPageServlet {
38 private static final long serialVersionUID = 7013060161686096950L;
40 public static final String BRIDGE_UID_PARAMETER_NAME = "bridgeUid";
41 public static final String EMAIL_PARAMETER_NAME = "email";
43 public static final String BRIDGE_CREATION_FAILED_PARAMETER_NAME = "bridgeCreationFailed";
44 public static final String BRIDGE_RECONFIGURATION_FAILED_PARAMETER_NAME = "bridgeReconfigurationFailed";
46 private static final String ERROR_MESSAGE_TEXT_PLACEHOLDER = "<!-- ERROR MESSAGE TEXT -->";
47 private static final String BRIDGE_UID_PLACEHOLDER = "<!-- BRIDGE UID -->";
48 private static final String EMAIL_PLACEHOLDER = "<!-- EMAIL -->";
49 private static final String THINGS_TEMPLATE_CODE_PLACEHOLDER = "<!-- THINGS TEMPLATE CODE -->";
51 private static final String LOCALE_OPTIONS_PLACEHOLDER = "<!-- LOCALE OPTIONS -->";
53 private static final String DEFAULT_LANGUAGE = "en";
54 private static final Set<String> SUPPORTED_LANGUAGES = Set.of("da", "nl", "en", "fr", "de", "it", "nb", "es");
56 private final Logger logger = LoggerFactory.getLogger(SuccessServlet.class);
58 private final LanguageProvider languageProvider;
59 private final ThingsTemplateGenerator templateGenerator;
62 * Creates a new {@link SuccessServlet}.
64 * @param resourceLoader Loader for resources.
65 * @param languageProvider Provider for the language to use as default selection.
67 public SuccessServlet(ResourceLoader resourceLoader, LanguageProvider languageProvider) {
68 super(resourceLoader);
69 this.languageProvider = languageProvider;
70 this.templateGenerator = new ThingsTemplateGenerator();
74 protected String handleGetRequest(HttpServletRequest request, HttpServletResponse response)
75 throws MieleHttpException, IOException {
76 String bridgeUidString = request.getParameter(BRIDGE_UID_PARAMETER_NAME);
77 if (bridgeUidString == null || bridgeUidString.isEmpty()) {
78 logger.warn("Success page is missing bridge UID.");
79 return getResourceLoader().loadResourceAsString("failure.html").replace(ERROR_MESSAGE_TEXT_PLACEHOLDER,
80 "Missing bridge UID.");
83 String email = request.getParameter(EMAIL_PARAMETER_NAME);
84 if (email == null || email.isEmpty()) {
85 logger.warn("Success page is missing e-mail address.");
86 return getResourceLoader().loadResourceAsString("failure.html").replace(ERROR_MESSAGE_TEXT_PLACEHOLDER,
87 "Missing e-mail address.");
90 ThingUID bridgeUid = null;
92 bridgeUid = new ThingUID(bridgeUidString);
93 } catch (IllegalArgumentException e) {
94 logger.warn("Success page received malformed bridge UID '{}'.", bridgeUidString);
95 return getResourceLoader().loadResourceAsString("failure.html").replace(ERROR_MESSAGE_TEXT_PLACEHOLDER,
96 "Malformed bridge UID.");
99 String skeleton = getResourceLoader().loadResourceAsString("success.html");
100 skeleton = renderErrorMessage(request, skeleton);
101 skeleton = renderBridgeUid(skeleton, bridgeUid);
102 skeleton = renderEmail(skeleton, email);
103 skeleton = renderLocaleSelection(skeleton);
104 skeleton = renderBridgeConfigurationTemplate(skeleton, bridgeUid, email);
108 private String renderErrorMessage(HttpServletRequest request, String skeleton) {
109 if (ServletUtil.isParameterEnabled(request, BRIDGE_CREATION_FAILED_PARAMETER_NAME)) {
110 return skeleton.replace(ERROR_MESSAGE_TEXT_PLACEHOLDER,
111 "<div class=\"alert alert-danger\" role=\"alert\">Could not auto configure the bridge. Failed to approve the bridge from the inbox. Please try the configuration flow again.</div>");
112 } else if (ServletUtil.isParameterEnabled(request, BRIDGE_RECONFIGURATION_FAILED_PARAMETER_NAME)) {
113 return skeleton.replace(ERROR_MESSAGE_TEXT_PLACEHOLDER,
114 "<div class=\"alert alert-danger\" role=\"alert\">Could not auto reconfigure the bridge. Bridge thing or thing handler is not available. Please try the configuration flow again.</div>");
116 return skeleton.replace(ERROR_MESSAGE_TEXT_PLACEHOLDER, "");
120 private String renderBridgeUid(String skeleton, ThingUID bridgeUid) {
121 return skeleton.replace(BRIDGE_UID_PLACEHOLDER, bridgeUid.getAsString());
124 private String renderEmail(String skeleton, String email) {
125 return skeleton.replace(EMAIL_PLACEHOLDER, email);
128 private String renderLocaleSelection(String skeleton) {
129 String preSelectedLanguage = languageProvider.getLanguage().filter(SUPPORTED_LANGUAGES::contains)
130 .orElse(DEFAULT_LANGUAGE);
132 return skeleton.replace(LOCALE_OPTIONS_PLACEHOLDER,
133 SUPPORTED_LANGUAGES.stream().map(Language::fromCode).filter(Optional::isPresent).map(Optional::get)
135 .map(language -> createOptionTag(language, preSelectedLanguage.equals(language.getCode())))
136 .collect(Collectors.joining("\n")));
139 private String createOptionTag(Language language, boolean selected) {
140 String firstPart = " <option value=\"" + language.getCode() + "\"";
141 String secondPart = ">" + language.format() + "</option>";
143 return firstPart + " selected=\"selected\"" + secondPart;
145 return firstPart + secondPart;
149 private String renderBridgeConfigurationTemplate(String skeleton, ThingUID bridgeUid, String email) {
150 String bridgeTemplate = templateGenerator.createBridgeConfigurationTemplate(bridgeUid.getId(), email,
151 languageProvider.getLanguage().orElse("en"));
152 return skeleton.replace(THINGS_TEMPLATE_CODE_PLACEHOLDER, bridgeTemplate);
156 * A language representation for user display.
158 * @author Björn Lange - Initial contribution
160 private static final class Language implements Comparable<Language> {
161 private final String code;
162 private final String name;
164 private Language(String code, String name) {
170 * Gets the 2-letter language code for accessing the Miele Cloud service.
172 public String getCode() {
177 * Formats the language for displaying.
179 public String format() {
180 return name + " - " + code;
184 public int compareTo(Language other) {
185 return name.toUpperCase().compareTo(other.name.toUpperCase());
189 * Constructs a {@link Language} from a 2-letter language code.
191 * @param code 2-letter language code.
192 * @return An {@link Optional} wrapping the {@link Language} or an empty {@link Optional} if there is no
193 * representation for the given language code.
195 public static Optional<Language> fromCode(String code) {
196 Locale locale = new Locale(code);
197 String name = locale.getDisplayLanguage(locale);
198 if (name.isEmpty()) {
199 return Optional.empty();
201 return Optional.of(new Language(code, name));