From d49f100ab60bc06206a828a096f0c971553a1225 Mon Sep 17 00:00:00 2001 From: Andrew Fiddian-Green Date: Sun, 22 Oct 2023 00:30:51 +0100 Subject: [PATCH] [suggestion-finder] update xml schema, converters, and tests Signed-off-by: Andrew Fiddian-Green --- bundles/org.openhab.core.addon/.classpath | 7 -- .../schema/addon-1.0.0.xsd | 16 ++- .../core/addon/AddonDiscoveryMethod.java | 15 ++- ...eryServiceType.java => AddonInfoList.java} | 20 +++- .../core/addon/AddonMatchProperty.java | 11 +- .../xml/AddonDiscoveryMethodConverter.java | 61 +++++++++++ .../internal/xml/AddonInfoConverter.java | 21 +--- .../internal/xml/AddonInfoListConverter.java | 57 ++++++++++ .../internal/xml/AddonInfoListReader.java | 101 ++++++++++++++++++ .../addon/internal/xml/AddonInfoReader.java | 9 +- .../xml/AddonMatchPropertyConverter.java | 52 +++++++++ .../org.openhab.core.config.core/.classpath | 12 ++- .../core/xml/util/XmlDocumentReader.java | 17 +++ .../finders/BaseAddonSuggestionFinder.java | 3 + .../finders/MDNSAddonSuggestionFinder.java | 10 +- .../finders/UpnpAddonSuggestionFinder.java | 6 +- .../AddonSuggestionFinderServiceTests.java | 7 +- .../core/addon/xml/test/AddonInfoTest.java | 31 +++++- .../OH-INF/addon/addon.xml | 17 +++ 19 files changed, 414 insertions(+), 59 deletions(-) rename bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/{AddonDiscoveryServiceType.java => AddonInfoList.java} (54%) create mode 100644 bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonDiscoveryMethodConverter.java create mode 100644 bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListConverter.java create mode 100644 bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListReader.java create mode 100644 bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonMatchPropertyConverter.java diff --git a/bundles/org.openhab.core.addon/.classpath b/bundles/org.openhab.core.addon/.classpath index 634118741ac..e591f47ba53 100644 --- a/bundles/org.openhab.core.addon/.classpath +++ b/bundles/org.openhab.core.addon/.classpath @@ -29,12 +29,5 @@ - - - - - - - diff --git a/bundles/org.openhab.core.addon/schema/addon-1.0.0.xsd b/bundles/org.openhab.core.addon/schema/addon-1.0.0.xsd index 32f5e0bd1ce..0e265cad6c4 100644 --- a/bundles/org.openhab.core.addon/schema/addon-1.0.0.xsd +++ b/bundles/org.openhab.core.addon/schema/addon-1.0.0.xsd @@ -28,7 +28,7 @@ - + @@ -81,11 +81,23 @@ + + + + + + - + + + + + + + diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryMethod.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryMethod.java index 967cb868b11..2e923a2f965 100644 --- a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryMethod.java +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryMethod.java @@ -24,13 +24,12 @@ */ @NonNullByDefault public class AddonDiscoveryMethod { - private @Nullable String serviceType; + private @NonNullByDefault({}) String serviceType; private @Nullable String mdnsServiceType; private @Nullable List matchProperties; - public AddonDiscoveryServiceType getServiceType() { - String serviceType = this.serviceType; - return AddonDiscoveryServiceType.valueOf(serviceType != null ? serviceType.toUpperCase() : ""); + public String getServiceType() { + return serviceType.toLowerCase(); } public String getMdnsServiceType() { @@ -43,17 +42,17 @@ public List getMatchProperties() { return matchProperties != null ? matchProperties : List.of(); } - public AddonDiscoveryMethod setServiceType(AddonDiscoveryServiceType serviceType) { - this.serviceType = serviceType.name().toLowerCase(); + public AddonDiscoveryMethod setServiceType(String serviceType) { + this.serviceType = serviceType.toLowerCase(); return this; } - public AddonDiscoveryMethod setMdnsServiceType(String mdnsServiceType) { + public AddonDiscoveryMethod setMdnsServiceType(@Nullable String mdnsServiceType) { this.mdnsServiceType = mdnsServiceType; return this; } - public AddonDiscoveryMethod setMatchProperties(List matchProperties) { + public AddonDiscoveryMethod setMatchProperties(@Nullable List matchProperties) { this.matchProperties = matchProperties; return this; } diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryServiceType.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonInfoList.java similarity index 54% rename from bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryServiceType.java rename to bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonInfoList.java index a9526b50246..6638d9dec49 100644 --- a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonDiscoveryServiceType.java +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonInfoList.java @@ -12,15 +12,27 @@ */ package org.openhab.core.addon; +import java.util.List; + import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; /** - * Enum of different supported discovery types. + * DTO containing a list of {@code AddonInfo} * * @author Andrew Fiddian-Green - Initial contribution */ @NonNullByDefault -public enum AddonDiscoveryServiceType { - MDNS, - UPNP +public class AddonInfoList { + protected @Nullable List addons; + + public List getAddons() { + List addons = this.addons; + return addons != null ? addons : List.of(); + } + + public AddonInfoList setAddons(@Nullable List addons) { + this.addons = addons; + return this; + } } diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonMatchProperty.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonMatchProperty.java index 06943b64fa5..c85040a535b 100644 --- a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonMatchProperty.java +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonMatchProperty.java @@ -13,7 +13,6 @@ package org.openhab.core.addon; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; /** * DTO for serialization of a property match regular expression. @@ -22,8 +21,8 @@ */ @NonNullByDefault public class AddonMatchProperty { - private @Nullable String name; - private @Nullable String regex; + private @NonNullByDefault({}) String name; + private @NonNullByDefault({}) String regex; public AddonMatchProperty(String name, String regex) { this.name = name; @@ -31,12 +30,10 @@ public AddonMatchProperty(String name, String regex) { } public String getName() { - String name = this.name; - return name != null ? name : ""; + return name; } public String getRegex() { - String regex = this.regex; - return regex != null ? regex : ""; + return regex; } } diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonDiscoveryMethodConverter.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonDiscoveryMethodConverter.java new file mode 100644 index 00000000000..39110721aec --- /dev/null +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonDiscoveryMethodConverter.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.addon.internal.xml; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.addon.AddonDiscoveryMethod; +import org.openhab.core.addon.AddonMatchProperty; +import org.openhab.core.config.core.xml.util.GenericUnmarshaller; +import org.openhab.core.config.core.xml.util.NodeIterator; + +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +/** + * The {@link AddonDiscoveryMethodConverter} is a concrete implementation of the {@code XStream} {@link Converter} + * interface used to convert add-on discovery method information within an XML document into a + * {@link AddonDiscoveryMethod} object. + * + * @author Andrew Fiddian-Green - Initial contribution + */ +@NonNullByDefault +public class AddonDiscoveryMethodConverter extends GenericUnmarshaller { + + public AddonDiscoveryMethodConverter() { + super(AddonDiscoveryMethod.class); + } + + @Override + public @Nullable Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + List nodes = (List) context.convertAnother(context, List.class); + NodeIterator nodeIterator = new NodeIterator(nodes); + + String serviceType = requireNonEmpty((String) nodeIterator.nextValue("service-type", true), + "Service type is null or empty"); + + String mdnsServiceType = (String) nodeIterator.nextValue("mdns-service-type", false); + + Object object = nodeIterator.nextList("match-properties", false); + List matchProperties = !(object instanceof List list) ? null + : list.stream().filter(e -> (e instanceof AddonMatchProperty)).map(e -> ((AddonMatchProperty) e)) + .toList(); + + nodeIterator.assertEndOfType(); + + return new AddonDiscoveryMethod().setServiceType(serviceType).setMdnsServiceType(mdnsServiceType) + .setMatchProperties(matchProperties); + } +} diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoConverter.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoConverter.java index a72fe457bba..2e1db84409a 100644 --- a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoConverter.java +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoConverter.java @@ -13,7 +13,6 @@ package org.openhab.core.addon.internal.xml; import java.net.URI; -import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -39,6 +38,7 @@ * @author Michael Grammling - Initial contribution * @author Andre Fuechsel - Made author tag optional * @author Jan N. Klug - Refactored to cover all add-ons + * @author Andrew Fiddian-Green - Added discovery methods */ @NonNullByDefault public class AddonInfoConverter extends GenericUnmarshaller { @@ -109,21 +109,10 @@ public AddonInfoConverter() { addonInfo.withConfigDescriptionURI(configDescriptionURI); - List discoveryMethods = null; - while (true) { - Object value = nodeIterator.nextValue("discovery-method", false); - if (value instanceof AddonDiscoveryMethod discoveryMethod) { - if (discoveryMethods == null) { - discoveryMethods = new ArrayList<>(); - } - discoveryMethods.add(discoveryMethod); - } else { - break; - } - } - if (discoveryMethods != null) { - addonInfo.withDiscoveryMethods(discoveryMethods); - } + Object object = nodeIterator.nextList("discovery-methods", false); + addonInfo.withDiscoveryMethods(!(object instanceof List list) ? null + : list.stream().filter(e -> (e instanceof AddonDiscoveryMethod)).map(e -> ((AddonDiscoveryMethod) e)) + .toList()); nodeIterator.assertEndOfType(); diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListConverter.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListConverter.java new file mode 100644 index 00000000000..9f745f46bae --- /dev/null +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListConverter.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.addon.internal.xml; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.addon.AddonInfo; +import org.openhab.core.addon.AddonInfoList; +import org.openhab.core.config.core.xml.util.GenericUnmarshaller; +import org.openhab.core.config.core.xml.util.NodeIterator; + +import com.thoughtworks.xstream.converters.Converter; +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +/** + * The {@link AddonInfoListConverter} is a concrete implementation of the {@code XStream} {@link Converter} + * interface used to convert a list of add-on information within an XML document into a list of {@link AddonInfo} + * objects. + * + * @author Andrew Fiddian-Green - Initial contribution + */ +@NonNullByDefault +public class AddonInfoListConverter extends GenericUnmarshaller { + + public AddonInfoListConverter() { + super(AddonInfoList.class); + } + + @Override + public @Nullable Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + List nodes = (List) context.convertAnother(context, List.class); + NodeIterator nodeIterator = new NodeIterator(nodes); + + Object object = nodeIterator.nextList("addons", false); + List addons = (object instanceof List list) + ? list.stream().filter(e -> (e instanceof AddonInfoXmlResult)).map(e -> (AddonInfoXmlResult) e) + .map(r -> r.addonInfo()).toList() + : null; + + nodeIterator.assertEndOfType(); + + return new AddonInfoList().setAddons(addons); + } +} diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListReader.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListReader.java new file mode 100644 index 00000000000..28819af791d --- /dev/null +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoListReader.java @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.addon.internal.xml; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.addon.AddonDiscoveryMethod; +import org.openhab.core.addon.AddonInfoList; +import org.openhab.core.addon.AddonMatchProperty; +import org.openhab.core.config.core.ConfigDescription; +import org.openhab.core.config.core.ConfigDescriptionParameter; +import org.openhab.core.config.core.ConfigDescriptionParameterGroup; +import org.openhab.core.config.core.FilterCriteria; +import org.openhab.core.config.core.xml.ConfigDescriptionConverter; +import org.openhab.core.config.core.xml.ConfigDescriptionParameterConverter; +import org.openhab.core.config.core.xml.ConfigDescriptionParameterGroupConverter; +import org.openhab.core.config.core.xml.FilterCriteriaConverter; +import org.openhab.core.config.core.xml.util.NodeAttributes; +import org.openhab.core.config.core.xml.util.NodeAttributesConverter; +import org.openhab.core.config.core.xml.util.NodeList; +import org.openhab.core.config.core.xml.util.NodeListConverter; +import org.openhab.core.config.core.xml.util.NodeValue; +import org.openhab.core.config.core.xml.util.NodeValueConverter; +import org.openhab.core.config.core.xml.util.XmlDocumentReader; + +import com.thoughtworks.xstream.XStream; + +/** + * The {@link AddonInfoListReader} reads XML documents, which contain the {@code binding} XML tag, and converts them to + * a List of {@link AddonInfoXmlResult} objects. + *

+ * This reader uses {@code XStream} and {@code StAX} to parse and convert the XML document. + * + * @author Andrew Fiddian-Green - Initial contribution + */ +@NonNullByDefault +public class AddonInfoListReader extends XmlDocumentReader { + + /** + * The default constructor of this class. + */ + public AddonInfoListReader() { + ClassLoader classLoader = AddonInfoListReader.class.getClassLoader(); + if (classLoader != null) { + super.setClassLoader(classLoader); + } + } + + @Override + protected void registerConverters(XStream xstream) { + xstream.registerConverter(new NodeAttributesConverter()); + xstream.registerConverter(new NodeListConverter()); + xstream.registerConverter(new NodeValueConverter()); + xstream.registerConverter(new AddonInfoListConverter()); + xstream.registerConverter(new AddonInfoConverter()); + xstream.registerConverter(new ConfigDescriptionConverter()); + xstream.registerConverter(new ConfigDescriptionParameterConverter()); + xstream.registerConverter(new ConfigDescriptionParameterGroupConverter()); + xstream.registerConverter(new FilterCriteriaConverter()); + xstream.registerConverter(new AddonDiscoveryMethodConverter()); + xstream.registerConverter(new AddonMatchPropertyConverter()); + } + + @Override + protected void registerAliases(XStream xstream) { + xstream.alias("addons", NodeList.class); + xstream.alias("addon", AddonInfoXmlResult.class); + xstream.alias("name", NodeValue.class); + xstream.alias("description", NodeValue.class); + xstream.alias("type", NodeValue.class); + xstream.alias("connection", NodeValue.class); + xstream.alias("countries", NodeValue.class); + xstream.alias("config-description", ConfigDescription.class); + xstream.alias("config-description-ref", NodeAttributes.class); + xstream.alias("parameter", ConfigDescriptionParameter.class); + xstream.alias("parameter-group", ConfigDescriptionParameterGroup.class); + xstream.alias("options", NodeList.class); + xstream.alias("option", NodeValue.class); + xstream.alias("filter", List.class); + xstream.alias("criteria", FilterCriteria.class); + xstream.alias("service-id", NodeValue.class); + xstream.alias("discovery-methods", NodeList.class); + xstream.alias("discovery-method", AddonDiscoveryMethod.class); + xstream.alias("service-type", NodeValue.class); + xstream.alias("mdns-service-type", NodeValue.class); + xstream.alias("match-properties", NodeList.class); + xstream.alias("match-property", AddonMatchProperty.class); + xstream.alias("regex", NodeValue.class); + } +} diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoReader.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoReader.java index b5f4ec981ed..b5297e588b5 100644 --- a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoReader.java +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonInfoReader.java @@ -28,6 +28,7 @@ import org.openhab.core.config.core.xml.util.NodeAttributes; import org.openhab.core.config.core.xml.util.NodeAttributesConverter; import org.openhab.core.config.core.xml.util.NodeList; +import org.openhab.core.config.core.xml.util.NodeListConverter; import org.openhab.core.config.core.xml.util.NodeValue; import org.openhab.core.config.core.xml.util.NodeValueConverter; import org.openhab.core.config.core.xml.util.XmlDocumentReader; @@ -61,12 +62,15 @@ public AddonInfoReader() { @Override protected void registerConverters(XStream xstream) { xstream.registerConverter(new NodeAttributesConverter()); + xstream.registerConverter(new NodeListConverter()); xstream.registerConverter(new NodeValueConverter()); xstream.registerConverter(new AddonInfoConverter()); xstream.registerConverter(new ConfigDescriptionConverter()); xstream.registerConverter(new ConfigDescriptionParameterConverter()); xstream.registerConverter(new ConfigDescriptionParameterGroupConverter()); xstream.registerConverter(new FilterCriteriaConverter()); + xstream.registerConverter(new AddonDiscoveryMethodConverter()); + xstream.registerConverter(new AddonMatchPropertyConverter()); } @Override @@ -86,9 +90,12 @@ protected void registerAliases(XStream xstream) { xstream.alias("filter", List.class); xstream.alias("criteria", FilterCriteria.class); xstream.alias("service-id", NodeValue.class); + xstream.alias("discovery-methods", NodeList.class); + xstream.alias("discovery-method", AddonDiscoveryMethod.class); xstream.alias("service-type", NodeValue.class); xstream.alias("mdns-service-type", NodeValue.class); - xstream.alias("discovery-method", AddonDiscoveryMethod.class); + xstream.alias("match-properties", NodeList.class); xstream.alias("match-property", AddonMatchProperty.class); + xstream.alias("regex", NodeValue.class); } } diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonMatchPropertyConverter.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonMatchPropertyConverter.java new file mode 100644 index 00000000000..f8f5321d9de --- /dev/null +++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/internal/xml/AddonMatchPropertyConverter.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.addon.internal.xml; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.addon.AddonMatchProperty; +import org.openhab.core.config.core.xml.util.GenericUnmarshaller; +import org.openhab.core.config.core.xml.util.NodeIterator; + +import com.thoughtworks.xstream.converters.UnmarshallingContext; +import com.thoughtworks.xstream.io.HierarchicalStreamReader; + +/** + * The {@link AddonMatchPropertyConverter} is a concrete implementation of the {@code XStream} {@link Converter} + * interface used to convert add-on discovery method match property information within an XML document into a + * {@link AddonMatchProperty} object. + * + * @author Andrew Fiddian-Green - Initial contribution + */ +@NonNullByDefault +public class AddonMatchPropertyConverter extends GenericUnmarshaller { + + public AddonMatchPropertyConverter() { + super(AddonMatchProperty.class); + } + + @Override + public @Nullable Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + List nodes = (List) context.convertAnother(context, List.class); + NodeIterator nodeIterator = new NodeIterator(nodes); + + String name = requireNonEmpty((String) nodeIterator.nextValue("name", true), "Name is null or empty"); + String regex = requireNonEmpty((String) nodeIterator.nextValue("regex", true), "Regex is null or empty"); + + nodeIterator.assertEndOfType(); + + return new AddonMatchProperty(name, regex); + } +} diff --git a/bundles/org.openhab.core.config.core/.classpath b/bundles/org.openhab.core.config.core/.classpath index 5a77c00dbc1..ae05ef201a9 100644 --- a/bundles/org.openhab.core.config.core/.classpath +++ b/bundles/org.openhab.core.config.core/.classpath @@ -6,7 +6,12 @@ - + + + + + + @@ -31,5 +36,10 @@ + + + + + diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/xml/util/XmlDocumentReader.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/xml/util/XmlDocumentReader.java index ba3f30a4a55..449b11c12e2 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/xml/util/XmlDocumentReader.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/xml/util/XmlDocumentReader.java @@ -19,6 +19,7 @@ import org.eclipse.jdt.annotation.Nullable; import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.XStreamException; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.io.xml.StaxDriver; @@ -104,4 +105,20 @@ protected void configureSecurity(XStream xstream) { public @Nullable T readFromXML(URL xmlURL) throws ConversionException { return (@Nullable T) xstream.fromXML(xmlURL); } + + /** + * Reads the XML document containing a specific XML tag from the specified xml string and converts it to the + * according object. + *

+ * This method returns {@code null} if the given URL is {@code null}. + * + * @param xml a string containing the XML document to be read. + * @return the conversion result object (could be null). + * @throws XStreamException if the object cannot be deserialized. + * @throws ConversionException if the specified document contains invalid content + */ + @SuppressWarnings("unchecked") + public @Nullable T readFromXML(String xml) throws ConversionException { + return (@Nullable T) xstream.fromXML(xml); + } } diff --git a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/BaseAddonSuggestionFinder.java b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/BaseAddonSuggestionFinder.java index f93b0e2e223..dbc07c1a60b 100644 --- a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/BaseAddonSuggestionFinder.java +++ b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/BaseAddonSuggestionFinder.java @@ -30,8 +30,11 @@ @NonNullByDefault public abstract class BaseAddonSuggestionFinder implements AddonSuggestionFinder { + protected static final String ADDON_SUGGESTION_FINDER = "-addon-suggestion-finder"; + protected final List addonCandidates = Collections.synchronizedList(new ArrayList<>()); protected final Set addonSuggestionUIDs = ConcurrentHashMap.newKeySet(); + protected boolean scanDone; public Set getAddonSuggestionUIDs() { diff --git a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/MDNSAddonSuggestionFinder.java b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/MDNSAddonSuggestionFinder.java index 9823b74f274..3618167c252 100644 --- a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/MDNSAddonSuggestionFinder.java +++ b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/MDNSAddonSuggestionFinder.java @@ -24,7 +24,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.addon.AddonDiscoveryMethod; -import org.openhab.core.addon.AddonDiscoveryServiceType; import org.openhab.core.addon.AddonInfo; import org.openhab.core.io.transport.mdns.MDNSClient; import org.osgi.service.component.annotations.Activate; @@ -40,7 +39,8 @@ @Component(service = AddonSuggestionFinder.class, name = MDNSAddonSuggestionFinder.SERVICE_NAME) public class MDNSAddonSuggestionFinder extends BaseAddonSuggestionFinder { - public static final String SERVICE_NAME = "mdns-addon-suggestion-finder"; + public static final String SERVICE_TYPE = "mdns"; + public static final String SERVICE_NAME = SERVICE_TYPE + ADDON_SUGGESTION_FINDER; /** * Anonymous ServiceListener implementation that ignores call-backs. @@ -71,7 +71,7 @@ public MDNSAddonSuggestionFinder(@Reference MDNSClient mdnsClient) { public void scanTask() { for (AddonInfo candidate : addonCandidates) { for (AddonDiscoveryMethod method : candidate.getDiscoveryMethods()) { - if (AddonDiscoveryServiceType.MDNS != method.getServiceType()) { + if (!SERVICE_TYPE.equals(method.getServiceType())) { continue; } Map map = method.getMatchProperties().stream() @@ -96,8 +96,8 @@ && propertyMatches(map, "name", service.getName()) @Override public void setAddonCandidates(List candidates) { super.setAddonCandidates(candidates); - addonCandidates.forEach( - c -> c.getDiscoveryMethods().stream().filter(m -> AddonDiscoveryServiceType.MDNS == m.getServiceType()) + addonCandidates + .forEach(c -> c.getDiscoveryMethods().stream().filter(m -> SERVICE_TYPE.equals(m.getServiceType())) .forEach(m -> mdnsClient.addServiceListener(m.getMdnsServiceType(), noOp))); } } diff --git a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/UpnpAddonSuggestionFinder.java b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/UpnpAddonSuggestionFinder.java index ee539708bc3..fcce5ef2e3e 100644 --- a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/UpnpAddonSuggestionFinder.java +++ b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/finders/UpnpAddonSuggestionFinder.java @@ -19,7 +19,6 @@ import org.jupnp.UpnpService; import org.jupnp.model.meta.RemoteDevice; import org.openhab.core.addon.AddonDiscoveryMethod; -import org.openhab.core.addon.AddonDiscoveryServiceType; import org.openhab.core.addon.AddonInfo; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -34,7 +33,8 @@ @Component(service = AddonSuggestionFinder.class, name = UpnpAddonSuggestionFinder.SERVICE_NAME) public class UpnpAddonSuggestionFinder extends BaseAddonSuggestionFinder { - public static final String SERVICE_NAME = "upnp-addon-suggestion-finder"; + public static final String SERVICE_TYPE = "upnp"; + public static final String SERVICE_NAME = SERVICE_TYPE + ADDON_SUGGESTION_FINDER; private final UpnpService upnpService; @@ -52,7 +52,7 @@ public void scanTask() { // using nested for loops instead of forEach to allow external interruption return; } - if (AddonDiscoveryServiceType.UPNP != method.getServiceType()) { + if (!SERVICE_TYPE.equals(method.getServiceType())) { continue; } Map map = method.getMatchProperties().stream() diff --git a/bundles/org.openhab.core.config.discovery.addon/src/test/java/org/openhab/core/config/discovery/addon/tests/AddonSuggestionFinderServiceTests.java b/bundles/org.openhab.core.config.discovery.addon/src/test/java/org/openhab/core/config/discovery/addon/tests/AddonSuggestionFinderServiceTests.java index 4102369b6f8..7a6c0329776 100644 --- a/bundles/org.openhab.core.config.discovery.addon/src/test/java/org/openhab/core/config/discovery/addon/tests/AddonSuggestionFinderServiceTests.java +++ b/bundles/org.openhab.core.config.discovery.addon/src/test/java/org/openhab/core/config/discovery/addon/tests/AddonSuggestionFinderServiceTests.java @@ -57,7 +57,6 @@ import org.mockito.Mockito; import org.openhab.core.addon.Addon; import org.openhab.core.addon.AddonDiscoveryMethod; -import org.openhab.core.addon.AddonDiscoveryServiceType; import org.openhab.core.addon.AddonInfo; import org.openhab.core.addon.AddonInfoProvider; import org.openhab.core.addon.AddonMatchProperty; @@ -130,15 +129,15 @@ private void setupMockAddonService() { } private void setupMockAddonInfoProvider() { - AddonDiscoveryMethod hp = new AddonDiscoveryMethod().setServiceType(AddonDiscoveryServiceType.MDNS) + AddonDiscoveryMethod hp = new AddonDiscoveryMethod().setServiceType(MDNSAddonSuggestionFinder.SERVICE_TYPE) .setMatchProperties( List.of(new AddonMatchProperty("rp", ".*"), new AddonMatchProperty("ty", "hp (.*)"))) .setMdnsServiceType("_printer._tcp.local."); - AddonDiscoveryMethod hue1 = new AddonDiscoveryMethod().setServiceType(AddonDiscoveryServiceType.UPNP) + AddonDiscoveryMethod hue1 = new AddonDiscoveryMethod().setServiceType(UpnpAddonSuggestionFinder.SERVICE_TYPE) .setMatchProperties(List.of(new AddonMatchProperty("modelName", "Philips hue bridge"))); - AddonDiscoveryMethod hue2 = new AddonDiscoveryMethod().setServiceType(AddonDiscoveryServiceType.MDNS) + AddonDiscoveryMethod hue2 = new AddonDiscoveryMethod().setServiceType(MDNSAddonSuggestionFinder.SERVICE_TYPE) .setMdnsServiceType("_hue._tcp.local."); // create the mock diff --git a/itests/org.openhab.core.addon.tests/src/main/java/org/openhab/core/addon/xml/test/AddonInfoTest.java b/itests/org.openhab.core.addon.tests/src/main/java/org/openhab/core/addon/xml/test/AddonInfoTest.java index 1531c2ab4b8..62a49060580 100644 --- a/itests/org.openhab.core.addon.tests/src/main/java/org/openhab/core/addon/xml/test/AddonInfoTest.java +++ b/itests/org.openhab.core.addon.tests/src/main/java/org/openhab/core/addon/xml/test/AddonInfoTest.java @@ -12,8 +12,11 @@ */ package org.openhab.core.addon.xml.test; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.net.URI; import java.util.List; @@ -24,8 +27,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.openhab.core.addon.AddonDiscoveryMethod; import org.openhab.core.addon.AddonInfo; import org.openhab.core.addon.AddonInfoRegistry; +import org.openhab.core.addon.AddonMatchProperty; import org.openhab.core.config.core.ConfigDescription; import org.openhab.core.config.core.ConfigDescriptionParameter; import org.openhab.core.config.core.ConfigDescriptionRegistry; @@ -66,6 +71,30 @@ public void assertThatAddonInfoIsReadProperly() throws Exception { assertThat(addonInfo.getDescription(), is("The hue Binding integrates the Philips hue system. It allows to control hue lights.")); assertThat(addonInfo.getName(), is("hue Binding")); + + List discoveryMethods = addonInfo.getDiscoveryMethods(); + assertNotNull(discoveryMethods); + assertEquals(2, discoveryMethods.size()); + + AddonDiscoveryMethod discoveryMethod = discoveryMethods.get(0); + assertNotNull(discoveryMethod); + assertEquals("mdns", discoveryMethod.getServiceType()); + assertEquals("_hue._tcp.local.", discoveryMethod.getMdnsServiceType()); + List properties = discoveryMethod.getMatchProperties(); + assertNotNull(properties); + assertEquals(0, properties.size()); + + discoveryMethod = discoveryMethods.get(1); + assertNotNull(discoveryMethod); + assertEquals("upnp", discoveryMethod.getServiceType()); + assertEquals("", discoveryMethod.getMdnsServiceType()); + properties = discoveryMethod.getMatchProperties(); + assertNotNull(properties); + assertEquals(1, properties.size()); + AddonMatchProperty property = properties.get(0); + assertNotNull(property); + assertEquals("modelName", property.getName()); + assertEquals("Philips hue bridge", property.getRegex()); }); } diff --git a/itests/org.openhab.core.addon.tests/src/main/resources/test-bundle-pool/BundleInfoTest.bundle/OH-INF/addon/addon.xml b/itests/org.openhab.core.addon.tests/src/main/resources/test-bundle-pool/BundleInfoTest.bundle/OH-INF/addon/addon.xml index 4d351403227..9e5db0944bd 100644 --- a/itests/org.openhab.core.addon.tests/src/main/resources/test-bundle-pool/BundleInfoTest.bundle/OH-INF/addon/addon.xml +++ b/itests/org.openhab.core.addon.tests/src/main/resources/test-bundle-pool/BundleInfoTest.bundle/OH-INF/addon/addon.xml @@ -30,4 +30,21 @@ + + + + mdns + _hue._tcp.local. + + + upnp + + + modelName + Philips hue bridge + + + + +