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.bluetooth.govee.internal.readme;
15 import java.io.FileInputStream;
16 import java.io.StringWriter;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.List;
20 import java.util.stream.Collectors;
21 import java.util.stream.Stream;
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.xpath.XPath;
26 import javax.xml.xpath.XPathConstants;
27 import javax.xml.xpath.XPathExpression;
28 import javax.xml.xpath.XPathFactory;
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.openhab.binding.bluetooth.govee.internal.GoveeModel;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Node;
35 import org.w3c.dom.NodeList;
38 * @author Connor Petty - Initial contribution
42 public class ThingTypeTableGenerator {
44 public static void main(String[] args) throws Exception {
45 FileInputStream fileIS = new FileInputStream("src/main/resources/OH-INF/thing/thing-types.xml");
46 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
47 DocumentBuilder builder = builderFactory.newDocumentBuilder();
48 Document xmlDocument = builder.parse(fileIS);
49 XPath xPath = XPathFactory.newInstance().newXPath();
50 String expression = "/*[local-name()='thing-descriptions']/thing-type";
51 XPathExpression labelExpression = xPath.compile("label/text()");
52 XPathExpression descriptionExpression = xPath.compile("description/text()");
54 NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
56 List<ThingTypeData> thingTypeDataList = new ArrayList<>();
58 for (int i = 0; i < nodeList.getLength(); i++) {
59 Node node = nodeList.item(i);
60 ThingTypeData data = new ThingTypeData();
62 data.id = node.getAttributes().getNamedItem("id").getTextContent();
63 data.label = (String) labelExpression.evaluate(node, XPathConstants.STRING);
64 data.description = (String) descriptionExpression.evaluate(node, XPathConstants.STRING);
66 thingTypeDataList.add(data);
69 String[] headerRow = new String[] { "Thing Type ID", "Description", "Supported Models" };
71 List<String[]> rows = new ArrayList<>();
73 rows.addAll(thingTypeDataList.stream().map(ThingTypeTableGenerator::toRow).collect(Collectors.toList()));
75 int[] maxColumns = { maxColumnSize(rows, 0), maxColumnSize(rows, 1), maxColumnSize(rows, 2) };
77 StringWriter writer = new StringWriter();
81 writer.append(writeRow(maxColumns, row, ' ')).append('\n');
82 if (row == headerRow) {
83 writer.append(writeRow(maxColumns, new String[] { "", "", "" }, '-')).append('\n');
87 System.out.println(writer.toString());
90 private static String writeRow(int[] maxColumns, String[] row, char paddingChar) {
91 String prefix = "|" + paddingChar;
92 String infix = paddingChar + "|" + paddingChar;
93 String suffix = paddingChar + "|";
95 return Stream.of(0, 1, 2).map(i -> rightPad(row[i], maxColumns[i], paddingChar))
96 .collect(Collectors.joining(infix, prefix, suffix));
99 private static String rightPad(String str, int minLength, char paddingChar) {
100 if (str.length() >= minLength) {
103 StringBuilder builder = new StringBuilder(minLength);
105 while (builder.length() < minLength) {
106 builder.append(paddingChar);
108 return builder.toString();
111 private static int maxColumnSize(List<String[]> rows, int column) {
112 return rows.stream().map(row -> row[column].length()).max(Integer::compare).get();
115 private static class ThingTypeData {
116 private @Nullable String id;
117 private @Nullable String label;
118 private @Nullable String description;
121 private static String[] toRow(ThingTypeData data) {
122 return new String[] { data.id, //
124 modelsForType(data.id).stream().map(model -> model.name()).collect(Collectors.joining(",")) };
127 private static List<GoveeModel> modelsForType(@Nullable String typeUID) {
128 return Arrays.stream(GoveeModel.values()).filter(model -> model.getThingTypeUID().getId().equals(typeUID))
129 .collect(Collectors.toList());