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.mielecloud.internal.config.servlet;
15 import java.io.IOException;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.stream.Collectors;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.openhab.binding.mielecloud.internal.MieleCloudBindingConstants;
25 import org.openhab.binding.mielecloud.internal.config.ThingsTemplateGenerator;
26 import org.openhab.core.config.discovery.DiscoveryResult;
27 import org.openhab.core.config.discovery.inbox.Inbox;
28 import org.openhab.core.thing.Bridge;
29 import org.openhab.core.thing.Thing;
30 import org.openhab.core.thing.ThingRegistry;
31 import org.openhab.core.thing.ThingStatus;
34 * Servlet showing the account overview page.
36 * @author Björn Lange - Initial Contribution
39 public final class AccountOverviewServlet extends AbstractShowPageServlet {
40 private static final long serialVersionUID = -4551210904923220429L;
41 private static final String ACCOUNTS_SKELETON = "index.html";
43 private static final String BRIDGES_TITLE_PLACEHOLDER = "<!-- BRIDGES TITLE -->";
44 private static final String BRIDGES_PLACEHOLDER = "<!-- BRIDGES -->";
45 private static final String NO_SSL_WARNING_PLACEHOLDER = "<!-- NO SSL WARNING -->";
47 private final ThingRegistry thingRegistry;
48 private final Inbox inbox;
49 private final ThingsTemplateGenerator templateGenerator;
52 * Creates a new {@link AccountOverviewServlet}.
54 * @param resourceLoader Loader to use for resources.
55 * @param thingRegistry openHAB thing registry.
56 * @param inbox openHAB inbox for discovery results.
58 public AccountOverviewServlet(ResourceLoader resourceLoader, ThingRegistry thingRegistry, Inbox inbox) {
59 super(resourceLoader);
60 this.thingRegistry = thingRegistry;
62 this.templateGenerator = new ThingsTemplateGenerator();
66 protected String handleGetRequest(HttpServletRequest request, HttpServletResponse response)
67 throws MieleHttpException, IOException {
68 String skeleton = getResourceLoader().loadResourceAsString(ACCOUNTS_SKELETON);
69 skeleton = renderBridges(skeleton);
70 skeleton = renderSslWarning(request, skeleton);
74 private String renderBridges(String skeleton) {
75 List<Thing> bridges = thingRegistry.stream().filter(this::isMieleCloudBridge).collect(Collectors.toList());
76 if (bridges.isEmpty()) {
77 return renderNoBridges(skeleton);
79 return renderBridgesIntoSkeleton(skeleton, bridges);
83 private String renderNoBridges(String skeleton) {
84 return skeleton.replace(BRIDGES_TITLE_PLACEHOLDER, "There is no account paired at the moment.")
85 .replace(BRIDGES_PLACEHOLDER, "");
88 private String renderBridgesIntoSkeleton(String skeleton, List<Thing> bridges) {
89 StringBuilder builder = new StringBuilder();
92 Iterator<Thing> bridgeIterator = bridges.iterator();
93 while (bridgeIterator.hasNext()) {
94 builder.append(renderBridge(bridgeIterator.next(), index));
98 return skeleton.replace(BRIDGES_TITLE_PLACEHOLDER, "The following bridges are paired")
99 .replace(BRIDGES_PLACEHOLDER, builder.toString());
102 private String renderBridge(Thing bridge, int index) {
103 StringBuilder builder = new StringBuilder();
104 builder.append(" <li>\n");
106 String thingUid = bridge.getUID().getAsString();
107 String thingId = bridge.getUID().getId();
109 builder.append(thingUid.substring(0, thingUid.length() - thingId.length()));
111 builder.append(thingId);
113 builder.append(bridge.getConfiguration().get(MieleCloudBindingConstants.CONFIG_PARAM_EMAIL).toString());
114 builder.append("\n");
116 builder.append(" <span class=\"status ");
117 final ThingStatus status = bridge.getStatus();
118 if (status == ThingStatus.ONLINE) {
119 builder.append("online");
121 builder.append("offline");
123 builder.append("\">");
124 builder.append(status.toString());
125 builder.append("</span>\n");
127 builder.append(" <input class=\"trigger\" id=\"mielecloud-account-");
128 builder.append(thingId);
129 builder.append("\" type=\"checkbox\" name=\"things-file\" />\n");
131 builder.append(" <label for=\"mielecloud-account-");
132 builder.append(thingId);
133 builder.append("\">< ></label>\n");
135 builder.append(" <div class=\"things\">\n");
137 " <span class=\"legend\">You can use this things-file template to pair all available devices:</span>\n");
138 builder.append(" <div class=\"code-container\">\n");
140 " <a href=\"#\" onclick=\"copyCodeToClipboard(event, this);\" class=\"btn btn-outline-info btn-sm copy\">Copy</a>\n");
141 builder.append(" <textarea readonly>");
142 builder.append(generateConfigurationTemplate((Bridge) bridge));
143 builder.append("</textarea>\n");
144 builder.append(" </div>\n");
145 builder.append(" </div>\n");
146 builder.append(" </li>");
148 return builder.toString();
151 private String generateConfigurationTemplate(Bridge bridge) {
152 List<Thing> pairedThings = thingRegistry.stream().filter(thing -> isConnectedVia(thing, bridge))
153 .collect(Collectors.toList());
154 List<DiscoveryResult> discoveryResults = inbox.stream()
155 .filter(discoveryResult -> willConnectVia(discoveryResult, bridge)).collect(Collectors.toList());
157 return templateGenerator.createBridgeAndThingConfigurationTemplate(bridge, pairedThings, discoveryResults);
160 private boolean isConnectedVia(Thing thing, Bridge bridge) {
161 return bridge.getUID().equals(thing.getBridgeUID());
164 private boolean willConnectVia(DiscoveryResult discoveryResult, Bridge bridge) {
165 return bridge.getUID().equals(discoveryResult.getBridgeUID());
168 private boolean isMieleCloudBridge(Thing thing) {
169 return MieleCloudBindingConstants.THING_TYPE_BRIDGE.equals(thing.getThingTypeUID());
172 private String renderSslWarning(HttpServletRequest request, String skeleton) {
173 if (!request.isSecure()) {
174 return skeleton.replace(NO_SSL_WARNING_PLACEHOLDER,
176 <div class="alert alert-danger" role="alert">
177 Warning: We strongly advice to proceed only with SSL enabled for a secure data exchange.
178 See <a href="https://www.openhab.org/docs/installation/security.html">Securing access to openHAB</a> for details.
182 return skeleton.replace(NO_SSL_WARNING_PLACEHOLDER, "");