mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
Introduce metadata for all add-ons (#3050)
* Introduce addon.xml Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
parent
dd584779db
commit
3d54ee54d2
@ -66,7 +66,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.core.bundles</groupId>
|
||||
<artifactId>org.openhab.core.binding.xml</artifactId>
|
||||
<artifactId>org.openhab.core.addon.xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.core.binding.xml</name>
|
||||
<name>org.openhab.core.addon.xml</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
70
bundles/org.openhab.core.addon.xml/addon-1.0.0.xsd
Normal file
70
bundles/org.openhab.core.addon.xml/addon-1.0.0.xsd
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
targetNamespace="https://openhab.org/schemas/addon/v1.0.0">
|
||||
|
||||
<xs:import namespace="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
schemaLocation="https://openhab.org/schemas/config-description-1.0.0.xsd"/>
|
||||
|
||||
<xs:element name="addon">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="type" type="addonType"/>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="description" type="xs:string"/>
|
||||
<xs:element name="author" type="xs:string" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The organization maintaining the add-on (e.g. openHAB). Individual developer names should be avoided.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="connection" type="connectionType" minOccurs="0"/>
|
||||
<xs:element name="countries" type="countryType" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Comma-separated list of two-letter ISO country codes.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="service-id" type="xs:string" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The ID (service.pid or component.name) of the main add-on service, which can be configured through OSGi configuration admin service. Should only be used in combination with a config description definition. The default value is <type>.<name></xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:choice minOccurs="0">
|
||||
<xs:element name="config-description" type="config-description:configDescription"/>
|
||||
<xs:element name="config-description-ref" type="config-description:configDescriptionRef"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="config-description:idRestrictionPattern" use="required">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The id is used to construct the UID of this add-on to <type>-<name></xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
<xs:simpleType name="addonType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="automation"/>
|
||||
<xs:enumeration value="binding"/>
|
||||
<xs:enumeration value="misc"/>
|
||||
<xs:enumeration value="persistence"/>
|
||||
<xs:enumeration value="transformation"/>
|
||||
<xs:enumeration value="ui"/>
|
||||
<xs:enumeration value="voice"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="connectionType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="local"/>
|
||||
<xs:enumeration value="cloud"/>
|
||||
<xs:enumeration value="cloudDiscovery"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:simpleType name="countryType">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[a-z]{2}(,[a-z]{2})*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
</xs:schema>
|
@ -10,9 +10,9 @@
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.core.binding.xml</artifactId>
|
||||
<artifactId>org.openhab.core.addon.xml</artifactId>
|
||||
|
||||
<name>openHAB Core :: Bundles :: Binding XML</name>
|
||||
<name>openHAB Core :: Bundles :: Add-on XML</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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.xml.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionBuilder;
|
||||
import org.openhab.core.config.xml.util.ConverterAttributeMapValidator;
|
||||
import org.openhab.core.config.xml.util.GenericUnmarshaller;
|
||||
import org.openhab.core.config.xml.util.NodeIterator;
|
||||
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
|
||||
/**
|
||||
* The {@link AddonInfoConverter} is a concrete implementation of the {@code XStream} {@link Converter} interface used
|
||||
* to convert add-on information within an XML document into a {@link AddonInfoXmlResult} object.
|
||||
* This converter converts {@code addon} XML tags.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Andre Fuechsel - Made author tag optional
|
||||
* @author Jan N. Klug - Refactored to cover all add-ons
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AddonInfoConverter extends GenericUnmarshaller<AddonInfoXmlResult> {
|
||||
private static final String CONFIG_DESCRIPTION_URI_PLACEHOLDER = "addonInfoConverter:placeHolder";
|
||||
private final ConverterAttributeMapValidator attributeMapValidator;
|
||||
|
||||
public AddonInfoConverter() {
|
||||
super(AddonInfoXmlResult.class);
|
||||
|
||||
attributeMapValidator = new ConverterAttributeMapValidator(Map.of("id", true, "schemaLocation", false));
|
||||
}
|
||||
|
||||
private @Nullable ConfigDescription readConfigDescription(NodeIterator nodeIterator) {
|
||||
Object nextNode = nodeIterator.next();
|
||||
|
||||
if (nextNode != null) {
|
||||
if (nextNode instanceof ConfigDescription configDescription) {
|
||||
return configDescription;
|
||||
}
|
||||
|
||||
nodeIterator.revert();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
// read attributes
|
||||
Map<String, String> attributes = attributeMapValidator.readValidatedAttributes(reader);
|
||||
|
||||
String id = requireNonEmpty(attributes.get("id"), "Add-on id attribute is null or empty");
|
||||
|
||||
// set automatically extracted URI for a possible 'config-description' section
|
||||
context.put("config-description.uri", CONFIG_DESCRIPTION_URI_PLACEHOLDER);
|
||||
|
||||
// read values
|
||||
List<?> nodes = (List<?>) context.convertAnother(context, List.class);
|
||||
NodeIterator nodeIterator = new NodeIterator(nodes);
|
||||
|
||||
String type = requireNonEmpty((String) nodeIterator.nextValue("type", true), "Add-on type is null or empty");
|
||||
|
||||
String name = requireNonEmpty((String) nodeIterator.nextValue("name", true),
|
||||
"Add-on name attribute is null or empty");
|
||||
String description = requireNonEmpty((String) nodeIterator.nextValue("description", true),
|
||||
"Add-on description is null or empty");
|
||||
|
||||
AddonInfo.Builder addonInfo = AddonInfo.builder(id, type).withName(name).withDescription(description);
|
||||
addonInfo.withAuthor((String) nodeIterator.nextValue("author", false));
|
||||
addonInfo.withConnection((String) nodeIterator.nextValue("connection", false));
|
||||
|
||||
addonInfo.withServiceId((String) nodeIterator.nextValue("service-id", false));
|
||||
|
||||
String configDescriptionURI = nodeIterator.nextAttribute("config-description-ref", "uri", false);
|
||||
ConfigDescription configDescription = null;
|
||||
if (configDescriptionURI == null) {
|
||||
configDescription = readConfigDescription(nodeIterator);
|
||||
if (configDescription != null) {
|
||||
configDescriptionURI = configDescription.getUID().toString();
|
||||
// if config description is missing the URI, recreate it with correct URI
|
||||
if (CONFIG_DESCRIPTION_URI_PLACEHOLDER.equals(configDescriptionURI)) {
|
||||
configDescriptionURI = type + ":" + id;
|
||||
configDescription = ConfigDescriptionBuilder.create(URI.create(configDescriptionURI))
|
||||
.withParameterGroups(configDescription.getParameterGroups())
|
||||
.withParameters(configDescription.getParameters()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
addonInfo.withConfigDescriptionURI(configDescriptionURI);
|
||||
|
||||
nodeIterator.assertEndOfType();
|
||||
|
||||
// create object
|
||||
return new AddonInfoXmlResult(addonInfo.build(), configDescription);
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.xml.internal;
|
||||
package org.openhab.core.addon.xml.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -33,23 +33,24 @@ import org.openhab.core.config.xml.util.XmlDocumentReader;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfoReader} reads XML documents, which contain the {@code binding} XML tag,
|
||||
* and converts them to {@link BindingInfoXmlResult} objects.
|
||||
* The {@link AddonInfoReader} reads XML documents, which contain the {@code binding} XML tag,
|
||||
* and converts them to {@link AddonInfoXmlResult} objects.
|
||||
* <p>
|
||||
* This reader uses {@code XStream} and {@code StAX} to parse and convert the XML document.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Alex Tugarev - Extended by options and filter criteria
|
||||
* @author Chris Jackson - Add parameter groups
|
||||
* @author Jan N. Klug - Refactored to cover all add-ons
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfoReader extends XmlDocumentReader<BindingInfoXmlResult> {
|
||||
public class AddonInfoReader extends XmlDocumentReader<AddonInfoXmlResult> {
|
||||
|
||||
/**
|
||||
* The default constructor of this class.
|
||||
*/
|
||||
public BindingInfoReader() {
|
||||
ClassLoader classLoader = BindingInfoReader.class.getClassLoader();
|
||||
public AddonInfoReader() {
|
||||
ClassLoader classLoader = AddonInfoReader.class.getClassLoader();
|
||||
if (classLoader != null) {
|
||||
super.setClassLoader(classLoader);
|
||||
}
|
||||
@ -59,7 +60,7 @@ public class BindingInfoReader extends XmlDocumentReader<BindingInfoXmlResult> {
|
||||
protected void registerConverters(XStream xstream) {
|
||||
xstream.registerConverter(new NodeAttributesConverter());
|
||||
xstream.registerConverter(new NodeValueConverter());
|
||||
xstream.registerConverter(new BindingInfoConverter());
|
||||
xstream.registerConverter(new AddonInfoConverter());
|
||||
xstream.registerConverter(new ConfigDescriptionConverter());
|
||||
xstream.registerConverter(new ConfigDescriptionParameterConverter());
|
||||
xstream.registerConverter(new ConfigDescriptionParameterGroupConverter());
|
||||
@ -68,11 +69,11 @@ public class BindingInfoReader extends XmlDocumentReader<BindingInfoXmlResult> {
|
||||
|
||||
@Override
|
||||
protected void registerAliases(XStream xstream) {
|
||||
xstream.alias("binding", BindingInfoXmlResult.class);
|
||||
xstream.alias("addon", AddonInfoXmlResult.class);
|
||||
xstream.alias("name", NodeValue.class);
|
||||
xstream.alias("description", NodeValue.class);
|
||||
xstream.alias("author", NodeValue.class);
|
||||
xstream.alias("service-id", NodeValue.class);
|
||||
xstream.alias("type", NodeValue.class);
|
||||
xstream.alias("config-description", ConfigDescription.class);
|
||||
xstream.alias("config-description-ref", NodeAttributes.class);
|
||||
xstream.alias("parameter", ConfigDescriptionParameter.class);
|
||||
@ -81,5 +82,6 @@ public class BindingInfoReader extends XmlDocumentReader<BindingInfoXmlResult> {
|
||||
xstream.alias("option", NodeValue.class);
|
||||
xstream.alias("filter", List.class);
|
||||
xstream.alias("criteria", FilterCriteria.class);
|
||||
xstream.alias("service-id", NodeValue.class);
|
||||
}
|
||||
}
|
@ -10,11 +10,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.xml.internal;
|
||||
package org.openhab.core.addon.xml.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.BindingInfoProvider;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.xml.AbstractXmlConfigDescriptionProvider;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentProvider;
|
||||
@ -23,38 +21,37 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfoXmlProvider} is responsible managing any created
|
||||
* objects by a {@link BindingInfoReader} for a certain bundle.
|
||||
* The {@link AddonInfoXmlProvider} is responsible managing any created
|
||||
* objects by a {@link AddonInfoReader} for a certain bundle.
|
||||
* <p>
|
||||
* This implementation registers each {@link BindingInfo} object at the {@link XmlBindingInfoProvider} which is itself
|
||||
* registered as {@link BindingInfoProvider} service at the <i>OSGi</i> service registry.
|
||||
* This implementation registers each {@link AddonInfo} object at the {@link XmlAddonInfoProvider} which is itself
|
||||
* registered as {@link AddonInfoProvider} service at the <i>OSGi</i> service registry.
|
||||
* <p>
|
||||
* If there is a {@link ConfigDescription} object within the {@link BindingInfoXmlResult} object, it is added to the
|
||||
* If there is a {@link ConfigDescription} object within the {@link AddonInfoXmlResult} object, it is added to the
|
||||
* {@link AbstractXmlConfigDescriptionProvider} which is itself registered as <i>OSGi</i> service at the service
|
||||
* registry.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
*
|
||||
* @see BindingInfoXmlProviderFactory
|
||||
* @author Jan N. Klug - Refactored to cover all add-ons
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfoXmlProvider implements XmlDocumentProvider<BindingInfoXmlResult> {
|
||||
public class AddonInfoXmlProvider implements XmlDocumentProvider<AddonInfoXmlResult> {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(BindingInfoXmlProvider.class);
|
||||
private Logger logger = LoggerFactory.getLogger(AddonInfoXmlProvider.class);
|
||||
|
||||
private final Bundle bundle;
|
||||
|
||||
private final XmlBindingInfoProvider bindingInfoProvider;
|
||||
private final XmlAddonInfoProvider addonInfoProvider;
|
||||
private final AbstractXmlConfigDescriptionProvider configDescriptionProvider;
|
||||
|
||||
public BindingInfoXmlProvider(Bundle bundle, XmlBindingInfoProvider bindingInfoProvider,
|
||||
public AddonInfoXmlProvider(Bundle bundle, XmlAddonInfoProvider addonInfoProvider,
|
||||
AbstractXmlConfigDescriptionProvider configDescriptionProvider) throws IllegalArgumentException {
|
||||
if (bundle == null) {
|
||||
throw new IllegalArgumentException("The Bundle must not be null!");
|
||||
}
|
||||
|
||||
if (bindingInfoProvider == null) {
|
||||
throw new IllegalArgumentException("The XmlBindingInfoProvider must not be null!");
|
||||
if (addonInfoProvider == null) {
|
||||
throw new IllegalArgumentException("The XmlAddonInfoProvider must not be null!");
|
||||
}
|
||||
|
||||
if (configDescriptionProvider == null) {
|
||||
@ -62,13 +59,13 @@ public class BindingInfoXmlProvider implements XmlDocumentProvider<BindingInfoXm
|
||||
}
|
||||
|
||||
this.bundle = bundle;
|
||||
this.bindingInfoProvider = bindingInfoProvider;
|
||||
this.addonInfoProvider = addonInfoProvider;
|
||||
this.configDescriptionProvider = configDescriptionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addingObject(BindingInfoXmlResult bindingInfoXmlResult) {
|
||||
ConfigDescription configDescription = bindingInfoXmlResult.getConfigDescription();
|
||||
public synchronized void addingObject(AddonInfoXmlResult addonInfoXmlResult) {
|
||||
ConfigDescription configDescription = addonInfoXmlResult.configDescription();
|
||||
|
||||
if (configDescription != null) {
|
||||
try {
|
||||
@ -78,7 +75,7 @@ public class BindingInfoXmlProvider implements XmlDocumentProvider<BindingInfoXm
|
||||
}
|
||||
}
|
||||
|
||||
bindingInfoProvider.add(bundle, bindingInfoXmlResult.getBindingInfo());
|
||||
addonInfoProvider.add(bundle, addonInfoXmlResult.addonInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,7 +85,7 @@ public class BindingInfoXmlProvider implements XmlDocumentProvider<BindingInfoXm
|
||||
|
||||
@Override
|
||||
public synchronized void release() {
|
||||
this.bindingInfoProvider.removeAll(bundle);
|
||||
this.addonInfoProvider.removeAll(bundle);
|
||||
this.configDescriptionProvider.removeAll(bundle);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.xml.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionProvider;
|
||||
|
||||
/**
|
||||
* The {@link AddonInfoXmlResult} is an intermediate XML conversion result object which
|
||||
* contains a mandatory {@link AddonInfo} and an optional {@link ConfigDescription} object.
|
||||
* <p>
|
||||
* If a {@link ConfigDescription} object exists, it must be added to the according {@link ConfigDescriptionProvider}.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public record AddonInfoXmlResult(AddonInfo addonInfo, @Nullable ConfigDescription configDescription) {
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.xml.internal;
|
||||
package org.openhab.core.addon.xml.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
@ -25,15 +25,16 @@ import org.osgi.service.component.annotations.Reference;
|
||||
* Provides {@link ConfigDescription}s for bindings which are read from XML files.
|
||||
*
|
||||
* @author Simon Kaufmann - Initial contribution
|
||||
* @author Jan N. Klug - Refactored to cover all add-ons
|
||||
*/
|
||||
@Component(service = ConfigDescriptionProvider.class, immediate = true, property = { "openhab.scope=core.xml.binding" })
|
||||
@Component(service = ConfigDescriptionProvider.class, immediate = true, property = { "openhab.scope=core.xml.addon" })
|
||||
@NonNullByDefault
|
||||
public class BindingXmlConfigDescriptionProvider extends AbstractXmlConfigDescriptionProvider {
|
||||
public class AddonXmlConfigDescriptionProvider extends AbstractXmlConfigDescriptionProvider {
|
||||
|
||||
private final ConfigI18nLocalizationService configI18nService;
|
||||
|
||||
@Activate
|
||||
public BindingXmlConfigDescriptionProvider(final @Reference ConfigI18nLocalizationService configI18nService) {
|
||||
public AddonXmlConfigDescriptionProvider(final @Reference ConfigI18nLocalizationService configI18nService) {
|
||||
this.configI18nService = configI18nService;
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* 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.xml.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.addon.AddonI18nLocalizationService;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.addon.AddonInfoProvider;
|
||||
import org.openhab.core.common.ThreadPoolManager;
|
||||
import org.openhab.core.config.core.ConfigDescriptionProvider;
|
||||
import org.openhab.core.config.xml.AbstractXmlBasedProvider;
|
||||
import org.openhab.core.config.xml.AbstractXmlConfigDescriptionProvider;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentBundleTracker;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentProvider;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentProviderFactory;
|
||||
import org.openhab.core.config.xml.util.XmlDocumentReader;
|
||||
import org.openhab.core.service.ReadyService;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link XmlAddonInfoProvider} is a concrete implementation of the {@link AddonInfoProvider} service interface.
|
||||
* <p>
|
||||
* This implementation manages any {@link AddonInfo} objects associated to specific modules. If a specific module
|
||||
* disappears, any registered {@link AddonInfo} objects associated with that module are released.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Michael Grammling - Refactoring: Provider/Registry pattern is used, added locale support
|
||||
* @author Simon Kaufmann - factored out common aspects into {@link AbstractXmlBasedProvider}
|
||||
* @author Jan N. Klug - Refactored to cover all add-ons
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component
|
||||
public class XmlAddonInfoProvider extends AbstractXmlBasedProvider<String, AddonInfo>
|
||||
implements AddonInfoProvider, XmlDocumentProviderFactory<AddonInfoXmlResult> {
|
||||
|
||||
private static final String XML_DIRECTORY = "/OH-INF/addon/";
|
||||
public static final String READY_MARKER = "openhab.xmlAddonInfo";
|
||||
|
||||
private final AddonI18nLocalizationService addonI18nService;
|
||||
private final AbstractXmlConfigDescriptionProvider configDescriptionProvider;
|
||||
private final XmlDocumentBundleTracker<AddonInfoXmlResult> addonInfoTracker;
|
||||
private final Future<?> trackerJob;
|
||||
|
||||
@Activate
|
||||
public XmlAddonInfoProvider(final @Reference AddonI18nLocalizationService addonI18nService,
|
||||
final @Reference(target = "(openhab.scope=core.xml.addon)") ConfigDescriptionProvider configDescriptionProvider,
|
||||
final @Reference ReadyService readyService, ComponentContext componentContext) {
|
||||
this.addonI18nService = addonI18nService;
|
||||
this.configDescriptionProvider = (AbstractXmlConfigDescriptionProvider) configDescriptionProvider;
|
||||
|
||||
XmlDocumentReader<AddonInfoXmlResult> addonInfoReader = new AddonInfoReader();
|
||||
addonInfoTracker = new XmlDocumentBundleTracker<>(componentContext.getBundleContext(), XML_DIRECTORY,
|
||||
addonInfoReader, this, READY_MARKER, readyService);
|
||||
|
||||
ScheduledExecutorService scheduler = ThreadPoolManager
|
||||
.getScheduledPool(XmlDocumentBundleTracker.THREAD_POOL_NAME);
|
||||
trackerJob = scheduler.submit(addonInfoTracker::open);
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
trackerJob.cancel(true);
|
||||
addonInfoTracker.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized @Nullable AddonInfo getAddonInfo(@Nullable String id, @Nullable Locale locale) {
|
||||
return id == null ? null : get(id, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Set<AddonInfo> getAddonInfos(@Nullable Locale locale) {
|
||||
return new HashSet<>(getAll(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable AddonInfo localize(Bundle bundle, AddonInfo bindingInfo, @Nullable Locale locale) {
|
||||
return addonI18nService.createLocalizedAddonInfo(bundle, bindingInfo, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlDocumentProvider<AddonInfoXmlResult> createDocumentProvider(Bundle bundle) {
|
||||
return new AddonInfoXmlProvider(bundle, this, configDescriptionProvider);
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
targetNamespace="https://openhab.org/schemas/binding/v1.0.0">
|
||||
|
||||
<xs:import namespace="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
schemaLocation="https://openhab.org/schemas/config-description-1.0.0.xsd"/>
|
||||
|
||||
<xs:element name="binding">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="name" type="xs:string"/>
|
||||
<xs:element name="description" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="author" type="xs:string" minOccurs="0"/>
|
||||
<xs:element name="service-id" type="xs:string" minOccurs="0"/>
|
||||
<xs:choice minOccurs="0">
|
||||
<xs:element name="config-description" type="config-description:configDescription"/>
|
||||
<xs:element name="config-description-ref" type="config-description:configDescriptionRef"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="id" type="config-description:idRestrictionPattern" use="required"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
||||
</xs:schema>
|
@ -1,119 +0,0 @@
|
||||
/**
|
||||
* 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.binding.xml.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.xml.util.ConverterAttributeMapValidator;
|
||||
import org.openhab.core.config.xml.util.GenericUnmarshaller;
|
||||
import org.openhab.core.config.xml.util.NodeIterator;
|
||||
|
||||
import com.thoughtworks.xstream.converters.ConversionException;
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfoConverter} is a concrete implementation of the {@code XStream} {@link Converter} interface used
|
||||
* to convert binding information within an XML document
|
||||
* into a {@link BindingInfoXmlResult} object.
|
||||
* <p>
|
||||
* This converter converts {@code binding} XML tags.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Andre Fuechsel - Made author tag optional
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfoConverter extends GenericUnmarshaller<BindingInfoXmlResult> {
|
||||
|
||||
private ConverterAttributeMapValidator attributeMapValidator;
|
||||
|
||||
public BindingInfoConverter() {
|
||||
super(BindingInfoXmlResult.class);
|
||||
|
||||
attributeMapValidator = new ConverterAttributeMapValidator(
|
||||
new String[][] { { "id", "true" }, { "schemaLocation", "false" } });
|
||||
}
|
||||
|
||||
private @Nullable URI readConfigDescriptionURI(NodeIterator nodeIterator) throws ConversionException {
|
||||
String uriText = nodeIterator.nextAttribute("config-description-ref", "uri", false);
|
||||
|
||||
if (uriText != null) {
|
||||
try {
|
||||
return new URI(uriText);
|
||||
} catch (URISyntaxException ex) {
|
||||
throw new ConversionException(
|
||||
"The URI '" + uriText + "' in node " + "'config-description-ref' is invalid!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable ConfigDescription readConfigDescription(NodeIterator nodeIterator) {
|
||||
Object nextNode = nodeIterator.next();
|
||||
|
||||
if (nextNode != null) {
|
||||
if (nextNode instanceof ConfigDescription) {
|
||||
return (ConfigDescription) nextNode;
|
||||
}
|
||||
|
||||
nodeIterator.revert();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
// read attributes
|
||||
Map<String, String> attributes = attributeMapValidator.readValidatedAttributes(reader);
|
||||
|
||||
String id = requireNonEmpty(attributes.get("id"), "Binding id attribute is null or empty");
|
||||
|
||||
// set automatically extracted URI for a possible 'config-description' section
|
||||
context.put("config-description.uri", "binding:" + id);
|
||||
|
||||
// read values
|
||||
List<?> nodes = (List<?>) context.convertAnother(context, List.class);
|
||||
NodeIterator nodeIterator = new NodeIterator(nodes);
|
||||
|
||||
String name = requireNonEmpty((String) nodeIterator.nextValue("name", true),
|
||||
"Binding name attribute is null or empty");
|
||||
String description = (String) nodeIterator.nextValue("description", false);
|
||||
String author = (String) nodeIterator.nextValue("author", false);
|
||||
String serviceId = (String) nodeIterator.nextValue("service-id", false);
|
||||
|
||||
URI configDescriptionURI = readConfigDescriptionURI(nodeIterator);
|
||||
ConfigDescription configDescription = null;
|
||||
if (configDescriptionURI == null) {
|
||||
configDescription = readConfigDescription(nodeIterator);
|
||||
if (configDescription != null) {
|
||||
configDescriptionURI = configDescription.getUID();
|
||||
}
|
||||
}
|
||||
|
||||
nodeIterator.assertEndOfType();
|
||||
|
||||
// create object
|
||||
BindingInfo bindingInfo = new BindingInfo(id, name, description, author, serviceId, configDescriptionURI);
|
||||
return new BindingInfoXmlResult(bindingInfo, configDescription);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/**
|
||||
* 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.binding.xml.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionProvider;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfoXmlResult} is an intermediate XML conversion result object which
|
||||
* contains a mandatory {@link BindingInfo} and an optional {@link ConfigDescription} object.
|
||||
* <p>
|
||||
* If a {@link ConfigDescription} object exists, it must be added to the according {@link ConfigDescriptionProvider}.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfoXmlResult {
|
||||
|
||||
private BindingInfo bindingInfo;
|
||||
private @Nullable ConfigDescription configDescription;
|
||||
|
||||
public BindingInfoXmlResult(BindingInfo bindingInfo, @Nullable ConfigDescription configDescription) {
|
||||
this.bindingInfo = bindingInfo;
|
||||
this.configDescription = configDescription;
|
||||
}
|
||||
|
||||
public BindingInfo getBindingInfo() {
|
||||
return bindingInfo;
|
||||
}
|
||||
|
||||
public @Nullable ConfigDescription getConfigDescription() {
|
||||
return configDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BindingInfoXmlResult [bindingInfo=" + bindingInfo + ", configDescription=" + configDescription + "]";
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/**
|
||||
* 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.binding.xml.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.BindingInfoProvider;
|
||||
import org.openhab.core.binding.i18n.BindingI18nLocalizationService;
|
||||
import org.openhab.core.common.ThreadPoolManager;
|
||||
import org.openhab.core.config.core.ConfigDescriptionProvider;
|
||||
import org.openhab.core.config.xml.AbstractXmlBasedProvider;
|
||||
import org.openhab.core.config.xml.AbstractXmlConfigDescriptionProvider;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentBundleTracker;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentProvider;
|
||||
import org.openhab.core.config.xml.osgi.XmlDocumentProviderFactory;
|
||||
import org.openhab.core.config.xml.util.XmlDocumentReader;
|
||||
import org.openhab.core.service.ReadyService;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link XmlBindingInfoProvider} is a concrete implementation of the {@link BindingInfoProvider} service interface.
|
||||
* <p>
|
||||
* This implementation manages any {@link BindingInfo} objects associated to specific modules. If a specific module
|
||||
* disappears, any registered {@link BindingInfo} objects associated with that module are released.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Michael Grammling - Refactoring: Provider/Registry pattern is used, added locale support
|
||||
* @author Simon Kaufmann - factored out common aspects into {@link AbstractXmlBasedProvider}
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component
|
||||
public class XmlBindingInfoProvider extends AbstractXmlBasedProvider<String, BindingInfo>
|
||||
implements BindingInfoProvider, XmlDocumentProviderFactory<BindingInfoXmlResult> {
|
||||
|
||||
private static final String XML_DIRECTORY = "/OH-INF/binding/";
|
||||
public static final String READY_MARKER = "openhab.xmlBindingInfo";
|
||||
|
||||
private final BindingI18nLocalizationService bindingI18nService;
|
||||
private AbstractXmlConfigDescriptionProvider configDescriptionProvider;
|
||||
private @Nullable XmlDocumentBundleTracker<BindingInfoXmlResult> bindingInfoTracker;
|
||||
private final ReadyService readyService;
|
||||
private final ScheduledExecutorService scheduler = ThreadPoolManager
|
||||
.getScheduledPool(XmlDocumentBundleTracker.THREAD_POOL_NAME);
|
||||
private @Nullable Future<?> trackerJob;
|
||||
|
||||
@Activate
|
||||
public XmlBindingInfoProvider(final @Reference BindingI18nLocalizationService bindingI18nService,
|
||||
final @Reference(target = "(openhab.scope=core.xml.binding)") ConfigDescriptionProvider configDescriptionProvider,
|
||||
final @Reference ReadyService readyService) {
|
||||
this.bindingI18nService = bindingI18nService;
|
||||
this.configDescriptionProvider = (AbstractXmlConfigDescriptionProvider) configDescriptionProvider;
|
||||
this.readyService = readyService;
|
||||
}
|
||||
|
||||
@Activate
|
||||
public void activate(ComponentContext componentContext) {
|
||||
XmlDocumentReader<BindingInfoXmlResult> bindingInfoReader = new BindingInfoReader();
|
||||
bindingInfoTracker = new XmlDocumentBundleTracker<>(componentContext.getBundleContext(), XML_DIRECTORY,
|
||||
bindingInfoReader, this, READY_MARKER, readyService);
|
||||
trackerJob = scheduler.submit(() -> {
|
||||
bindingInfoTracker.open();
|
||||
});
|
||||
}
|
||||
|
||||
@Deactivate
|
||||
public void deactivate(ComponentContext componentContext) {
|
||||
Future<?> localTrackerJob = trackerJob;
|
||||
if (localTrackerJob != null && !localTrackerJob.isDone()) {
|
||||
localTrackerJob.cancel(true);
|
||||
trackerJob = null;
|
||||
}
|
||||
XmlDocumentBundleTracker<BindingInfoXmlResult> localBindingInfoTracker = bindingInfoTracker;
|
||||
if (localBindingInfoTracker != null) {
|
||||
localBindingInfoTracker.close();
|
||||
bindingInfoTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized @Nullable BindingInfo getBindingInfo(@Nullable String id, @Nullable Locale locale) {
|
||||
return id == null ? null : get(id, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Set<BindingInfo> getBindingInfos(@Nullable Locale locale) {
|
||||
return new HashSet<>(getAll(locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable BindingInfo localize(Bundle bundle, BindingInfo bindingInfo, @Nullable Locale locale) {
|
||||
return bindingI18nService.createLocalizedBindingInfo(bundle, bindingInfo, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XmlDocumentProvider<BindingInfoXmlResult> createDocumentProvider(Bundle bundle) {
|
||||
return new BindingInfoXmlProvider(bundle, this, configDescriptionProvider);
|
||||
}
|
||||
}
|
@ -12,20 +12,25 @@
|
||||
*/
|
||||
package org.openhab.core.io.rest.core.internal.addons;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
@ -41,10 +46,16 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.core.addon.Addon;
|
||||
import org.openhab.core.addon.AddonEventFactory;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.addon.AddonInfoRegistry;
|
||||
import org.openhab.core.addon.AddonService;
|
||||
import org.openhab.core.addon.AddonType;
|
||||
import org.openhab.core.auth.Role;
|
||||
import org.openhab.core.common.ThreadPoolManager;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionRegistry;
|
||||
import org.openhab.core.config.core.ConfigUtil;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventPublisher;
|
||||
import org.openhab.core.io.rest.JSONResponse;
|
||||
@ -52,6 +63,7 @@ import org.openhab.core.io.rest.LocaleService;
|
||||
import org.openhab.core.io.rest.RESTConstants;
|
||||
import org.openhab.core.io.rest.RESTResource;
|
||||
import org.openhab.core.io.rest.Stream2JSONInputStream;
|
||||
import org.openhab.core.io.rest.core.config.ConfigurationService;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
@ -105,13 +117,22 @@ public class AddonResource implements RESTResource {
|
||||
private final Set<AddonService> addonServices = new CopyOnWriteArraySet<>();
|
||||
private final EventPublisher eventPublisher;
|
||||
private final LocaleService localeService;
|
||||
private final ConfigurationService configurationService;
|
||||
private final AddonInfoRegistry addonInfoRegistry;
|
||||
private final ConfigDescriptionRegistry configDescriptionRegistry;
|
||||
|
||||
private @Context @NonNullByDefault({}) UriInfo uriInfo;
|
||||
|
||||
@Activate
|
||||
public AddonResource(final @Reference EventPublisher eventPublisher, final @Reference LocaleService localeService) {
|
||||
public AddonResource(final @Reference EventPublisher eventPublisher, final @Reference LocaleService localeService,
|
||||
final @Reference ConfigurationService configurationService,
|
||||
final @Reference AddonInfoRegistry addonInfoRegistry,
|
||||
final @Reference ConfigDescriptionRegistry configDescriptionRegistry) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.localeService = localeService;
|
||||
this.configurationService = configurationService;
|
||||
this.addonInfoRegistry = addonInfoRegistry;
|
||||
this.configDescriptionRegistry = configDescriptionRegistry;
|
||||
}
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
@ -270,6 +291,80 @@ public class AddonResource implements RESTResource {
|
||||
return Response.ok(null, MediaType.TEXT_PLAIN).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{addonId: [a-zA-Z_0-9-:]+}/config")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(operationId = "getAddonConfiguration", summary = "Get add-on configuration for given add-on ID.", responses = {
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))),
|
||||
@ApiResponse(responseCode = "404", description = "Add-on does not exist"),
|
||||
@ApiResponse(responseCode = "500", description = "Configuration can not be read due to internal error") })
|
||||
public Response getConfiguration(final @PathParam("addonId") @Parameter(description = "addon ID") String addonId,
|
||||
@QueryParam("serviceId") @Parameter(description = "service ID") @Nullable String serviceId) {
|
||||
try {
|
||||
AddonInfo addonInfo = addonInfoRegistry.getAddonInfo(addonId);
|
||||
if (addonInfo == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
Configuration configuration = configurationService.get(addonInfo.getServiceId());
|
||||
return configuration != null ? Response.ok(configuration.getProperties()).build()
|
||||
: Response.ok(Map.of()).build();
|
||||
} catch (IOException e) {
|
||||
logger.error("Cannot get configuration for service {}: {}", addonId, e.getMessage(), e);
|
||||
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{addonId: [a-zA-Z_0-9-:]+}/config")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(operationId = "updateAddonConfiguration", summary = "Updates an add-on configuration for given ID and returns the old configuration.", responses = {
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))),
|
||||
@ApiResponse(responseCode = "204", description = "No old configuration"),
|
||||
@ApiResponse(responseCode = "404", description = "Add-on does not exist"),
|
||||
@ApiResponse(responseCode = "500", description = "Configuration can not be updated due to internal error") })
|
||||
public Response updateConfiguration(@PathParam("addonId") @Parameter(description = "Add-on id") String addonId,
|
||||
@QueryParam("serviceId") @Parameter(description = "service ID") @Nullable String serviceId,
|
||||
@Nullable Map<String, Object> configuration) {
|
||||
try {
|
||||
AddonInfo addonInfo = addonInfoRegistry.getAddonInfo(addonId);
|
||||
if (addonInfo == null) {
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
}
|
||||
Configuration oldConfiguration = configurationService.get(addonInfo.getServiceId());
|
||||
configurationService.update(addonInfo.getServiceId(),
|
||||
new Configuration(normalizeConfiguration(configuration, addonId)));
|
||||
return oldConfiguration != null ? Response.ok(oldConfiguration.getProperties()).build()
|
||||
: Response.noContent().build();
|
||||
} catch (IOException ex) {
|
||||
logger.error("Cannot update configuration for service {}: {}", addonId, ex.getMessage(), ex);
|
||||
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
|
||||
String addonId) {
|
||||
if (properties == null || properties.isEmpty()) {
|
||||
return properties;
|
||||
}
|
||||
AddonInfo addonInfo = addonInfoRegistry.getAddonInfo(addonId);
|
||||
|
||||
if (addonInfo == null || addonInfo.getConfigDescriptionURI() == null) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
String configDescriptionURI = addonInfo.getConfigDescriptionURI();
|
||||
if (configDescriptionURI != null) {
|
||||
ConfigDescription configDesc = configDescriptionRegistry
|
||||
.getConfigDescription(URI.create(configDescriptionURI));
|
||||
if (configDesc != null) {
|
||||
return ConfigUtil.normalizeTypes(properties, List.of(configDesc));
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void postFailureEvent(String addonId, @Nullable String msg) {
|
||||
Event event = AddonEventFactory.createAddonFailureEvent(addonId, msg);
|
||||
eventPublisher.post(event);
|
||||
@ -302,12 +397,7 @@ public class AddonResource implements RESTResource {
|
||||
private Set<AddonType> getAddonTypesForService(AddonService addonService, Locale locale) {
|
||||
final Collator coll = Collator.getInstance(locale);
|
||||
coll.setStrength(Collator.PRIMARY);
|
||||
Set<AddonType> ret = new TreeSet<>(new Comparator<AddonType>() {
|
||||
@Override
|
||||
public int compare(AddonType o1, AddonType o2) {
|
||||
return coll.compare(o1.getLabel(), o2.getLabel());
|
||||
}
|
||||
});
|
||||
Set<AddonType> ret = new TreeSet<>((o1, o2) -> coll.compare(o1.getLabel(), o2.getLabel()));
|
||||
ret.addAll(addonService.getTypes(locale));
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,216 +0,0 @@
|
||||
/**
|
||||
* 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.io.rest.core.internal.binding;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.auth.Role;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.BindingInfoRegistry;
|
||||
import org.openhab.core.binding.dto.BindingInfoDTO;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionRegistry;
|
||||
import org.openhab.core.config.core.ConfigUtil;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.io.rest.LocaleService;
|
||||
import org.openhab.core.io.rest.RESTConstants;
|
||||
import org.openhab.core.io.rest.RESTResource;
|
||||
import org.openhab.core.io.rest.Stream2JSONInputStream;
|
||||
import org.openhab.core.io.rest.core.config.ConfigurationService;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
|
||||
import org.osgi.service.jaxrs.whiteboard.propertytypes.JSONRequired;
|
||||
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
|
||||
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName;
|
||||
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* This class acts as a REST resource for bindings and is registered with the
|
||||
* Jersey servlet.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
* @author Kai Kreuzer - refactored for using the OSGi JAX-RS connector
|
||||
* @author Yordan Zhelev - Added Swagger annotations
|
||||
* @author Franck Dechavanne - Added DTOs to ApiResponses
|
||||
* @author Markus Rathgeb - Migrated to JAX-RS Whiteboard Specification
|
||||
* @author Wouter Born - Migrated to OpenAPI annotations
|
||||
*/
|
||||
@Component
|
||||
@JaxrsResource
|
||||
@JaxrsName(BindingResource.PATH_BINDINGS)
|
||||
@JaxrsApplicationSelect("(" + JaxrsWhiteboardConstants.JAX_RS_NAME + "=" + RESTConstants.JAX_RS_NAME + ")")
|
||||
@JSONRequired
|
||||
@Path(BindingResource.PATH_BINDINGS)
|
||||
@RolesAllowed({ Role.ADMIN })
|
||||
@SecurityRequirement(name = "oauth2", scopes = { "admin" })
|
||||
@Tag(name = BindingResource.PATH_BINDINGS)
|
||||
@NonNullByDefault
|
||||
public class BindingResource implements RESTResource {
|
||||
|
||||
/** The URI path to this resource */
|
||||
public static final String PATH_BINDINGS = "bindings";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(BindingResource.class);
|
||||
|
||||
private final BindingInfoRegistry bindingInfoRegistry;
|
||||
private final ConfigurationService configurationService;
|
||||
private final ConfigDescriptionRegistry configDescRegistry;
|
||||
private final LocaleService localeService;
|
||||
|
||||
@Activate
|
||||
public BindingResource( //
|
||||
final @Reference BindingInfoRegistry bindingInfoRegistry,
|
||||
final @Reference ConfigurationService configurationService,
|
||||
final @Reference ConfigDescriptionRegistry configDescRegistry,
|
||||
final @Reference LocaleService localeService) {
|
||||
this.bindingInfoRegistry = bindingInfoRegistry;
|
||||
this.configurationService = configurationService;
|
||||
this.configDescRegistry = configDescRegistry;
|
||||
this.localeService = localeService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(operationId = "getBindings", summary = "Get all bindings.", responses = {
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = BindingInfoDTO.class), uniqueItems = true))) })
|
||||
public Response getAll(
|
||||
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @Parameter(description = "language") @Nullable String language) {
|
||||
final Locale locale = localeService.getLocale(language);
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(locale);
|
||||
|
||||
return Response.ok(new Stream2JSONInputStream(bindingInfos.stream().map(b -> map(b, locale)))).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{bindingId}/config")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(operationId = "getBindingConfiguration", summary = "Get binding configuration for given binding ID.", responses = {
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))),
|
||||
@ApiResponse(responseCode = "404", description = "Binding does not exist"),
|
||||
@ApiResponse(responseCode = "500", description = "Configuration can not be read due to internal error") })
|
||||
public Response getConfiguration(@PathParam("bindingId") @Parameter(description = "service ID") String bindingId) {
|
||||
try {
|
||||
String configId = getConfigId(bindingId);
|
||||
if (configId == null) {
|
||||
logger.warn("Cannot get config id for binding id '{}', probably because binding does not exist.",
|
||||
bindingId);
|
||||
return Response.status(404).build();
|
||||
}
|
||||
Configuration configuration = configurationService.get(configId);
|
||||
return configuration != null ? Response.ok(configuration.getProperties()).build()
|
||||
: Response.ok(Collections.emptyMap()).build();
|
||||
} catch (IOException ex) {
|
||||
logger.error("Cannot get configuration for service {}: {}", bindingId, ex.getMessage(), ex);
|
||||
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{bindingId}/config")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(operationId = "updateBindingConfiguration", summary = "Updates a binding configuration for given binding ID and returns the old configuration.", responses = {
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = String.class))),
|
||||
@ApiResponse(responseCode = "204", description = "No old configuration"),
|
||||
@ApiResponse(responseCode = "404", description = "Binding does not exist"),
|
||||
@ApiResponse(responseCode = "500", description = "Configuration can not be updated due to internal error") })
|
||||
public Response updateConfiguration(@PathParam("bindingId") @Parameter(description = "service ID") String bindingId,
|
||||
@Nullable Map<String, Object> configuration) {
|
||||
try {
|
||||
String configId = getConfigId(bindingId);
|
||||
if (configId == null) {
|
||||
logger.warn("Cannot get config id for binding id '{}', probably because binding does not exist.",
|
||||
bindingId);
|
||||
return Response.status(404).build();
|
||||
}
|
||||
Configuration oldConfiguration = configurationService.get(configId);
|
||||
configurationService.update(configId, new Configuration(normalizeConfiguration(configuration, bindingId)));
|
||||
return oldConfiguration != null ? Response.ok(oldConfiguration.getProperties()).build()
|
||||
: Response.noContent().build();
|
||||
} catch (IOException ex) {
|
||||
logger.error("Cannot update configuration for service {}: {}", bindingId, ex.getMessage(), ex);
|
||||
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable Map<String, Object> normalizeConfiguration(@Nullable Map<String, Object> properties,
|
||||
String bindingId) {
|
||||
if (properties == null || properties.isEmpty()) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
BindingInfo bindingInfo = this.bindingInfoRegistry.getBindingInfo(bindingId);
|
||||
if (bindingInfo == null || bindingInfo.getConfigDescriptionURI() == null) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
URI descURI = bindingInfo.getConfigDescriptionURI();
|
||||
if (descURI != null) {
|
||||
ConfigDescription configDesc = configDescRegistry.getConfigDescription(descURI);
|
||||
if (configDesc != null) {
|
||||
return ConfigUtil.normalizeTypes(properties, List.of(configDesc));
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private @Nullable String getConfigId(String bindingId) {
|
||||
BindingInfo bindingInfo = this.bindingInfoRegistry.getBindingInfo(bindingId);
|
||||
if (bindingInfo != null) {
|
||||
return bindingInfo.getServiceId();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private BindingInfoDTO map(BindingInfo bindingInfo, Locale locale) {
|
||||
URI configDescriptionURI = bindingInfo.getConfigDescriptionURI();
|
||||
return new BindingInfoDTO(bindingInfo.getUID(), bindingInfo.getName(), bindingInfo.getAuthor(),
|
||||
bindingInfo.getDescription(), configDescriptionURI != null ? configDescriptionURI.toString() : null);
|
||||
}
|
||||
}
|
@ -88,17 +88,14 @@ public class FeatureInstaller implements ConfigurationListener {
|
||||
public static final String EXTENSION_TYPE_TRANSFORMATION = "transformation";
|
||||
public static final String EXTENSION_TYPE_UI = "ui";
|
||||
public static final String EXTENSION_TYPE_VOICE = "voice";
|
||||
public static final List<String> EXTENSION_TYPES = List.of(EXTENSION_TYPE_AUTOMATION, EXTENSION_TYPE_BINDING,
|
||||
public static final Set<String> EXTENSION_TYPES = Set.of(EXTENSION_TYPE_AUTOMATION, EXTENSION_TYPE_BINDING,
|
||||
EXTENSION_TYPE_MISC, EXTENSION_TYPE_PERSISTENCE, EXTENSION_TYPE_TRANSFORMATION, EXTENSION_TYPE_UI,
|
||||
EXTENSION_TYPE_VOICE);
|
||||
|
||||
public static final String PREFIX = "openhab-";
|
||||
public static final String PREFIX_PACKAGE = "package-";
|
||||
public static final String SIMPLE_PACKAGE = "simple";
|
||||
public static final String MINIMAL_PACKAGE = "minimal";
|
||||
|
||||
public static final String STANDARD_PACKAGE = "standard";
|
||||
|
||||
private static final String CFG_REMOTE = "remote";
|
||||
private static final String PAX_URL_PID = "org.ops4j.pax.url.mvn";
|
||||
private static final String ADDONS_PID = "org.openhab.addons";
|
||||
@ -121,8 +118,6 @@ public class FeatureInstaller implements ConfigurationListener {
|
||||
// configuration as this must be waited for before trying to add feature repos
|
||||
private @Nullable Map<String, Object> configMapCache;
|
||||
|
||||
private @Nullable String currentPackage = null;
|
||||
|
||||
@Activate
|
||||
public FeatureInstaller(final @Reference ConfigurationAdmin configurationAdmin,
|
||||
final @Reference FeaturesService featuresService, final @Reference KarService karService,
|
||||
@ -226,11 +221,6 @@ public class FeatureInstaller implements ConfigurationListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
String getCurrentPackage() {
|
||||
return currentPackage;
|
||||
}
|
||||
|
||||
public void addAddon(String type, String id) {
|
||||
try {
|
||||
changeAddonConfig(type, id, Collection::add);
|
||||
@ -267,12 +257,13 @@ public class FeatureInstaller implements ConfigurationListener {
|
||||
Dictionary<String, Object> felixProperties = configurations[0].getProperties();
|
||||
String addonsDirectory = (String) felixProperties.get("felix.fileinstall.dir");
|
||||
if (addonsDirectory != null) {
|
||||
return Files.list(Path.of(addonsDirectory)).map(Path::getFileName).map(Path::toString)
|
||||
.filter(file -> file.endsWith(".kar"))
|
||||
try (Stream<Path> files = Files.list(Path.of(addonsDirectory))) {
|
||||
return files.map(Path::getFileName).map(Path::toString).filter(file -> file.endsWith(".kar"))
|
||||
.map(karFileName -> karFileName.substring(0, karFileName.lastIndexOf(".")))
|
||||
.allMatch(karRepos::contains);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
logger.warn("Could not determine addons folder, its content or the list of installed repositories!");
|
||||
@ -399,11 +390,11 @@ public class FeatureInstaller implements ConfigurationListener {
|
||||
|
||||
for (String type : EXTENSION_TYPES) {
|
||||
Object configValue = config.get(type);
|
||||
if (configValue instanceof String) {
|
||||
if (configValue instanceof String addonString) {
|
||||
try {
|
||||
Feature[] features = featuresService.listInstalledFeatures();
|
||||
String typePrefix = PREFIX + type + "-";
|
||||
Set<String> configFeatureNames = Arrays.stream(((String) configValue).split(",")) //
|
||||
Set<String> configFeatureNames = Arrays.stream(addonString.split(",")) //
|
||||
.map(String::strip) //
|
||||
.filter(not(String::isEmpty)) //
|
||||
.map(addon -> typePrefix + addon) //
|
||||
@ -531,9 +522,8 @@ public class FeatureInstaller implements ConfigurationListener {
|
||||
private boolean installPackage(final Map<String, Object> config) {
|
||||
boolean configChanged = false;
|
||||
Object packageName = config.get(OpenHAB.CFG_PACKAGE);
|
||||
if (packageName instanceof String) {
|
||||
currentPackage = (String) packageName;
|
||||
String fullName = PREFIX + PREFIX_PACKAGE + ((String) packageName).strip();
|
||||
if (packageName instanceof String currentPackage) {
|
||||
String fullName = PREFIX + PREFIX_PACKAGE + currentPackage.strip();
|
||||
if (!MINIMAL_PACKAGE.equals(currentPackage)) {
|
||||
configChanged = installFeature(fullName);
|
||||
}
|
||||
|
@ -13,20 +13,20 @@
|
||||
package org.openhab.core.karaf.internal;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.karaf.features.Feature;
|
||||
import org.apache.karaf.features.FeaturesService;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.addon.Addon;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.addon.AddonInfoRegistry;
|
||||
import org.openhab.core.addon.AddonService;
|
||||
import org.openhab.core.addon.AddonType;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.BindingInfoRegistry;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
@ -40,34 +40,32 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
*/
|
||||
@Component(name = "org.openhab.core.karafaddons")
|
||||
@NonNullByDefault
|
||||
public class KarafAddonService implements AddonService {
|
||||
private static final String ADDONS_CONTENTTYPE = "application/vnd.openhab.feature;type=karaf";
|
||||
private static final String ADDONS_CONTENT_TYPE = "application/vnd.openhab.feature;type=karaf";
|
||||
private static final String ADDONS_AUTHOR = "openHAB";
|
||||
private static final List<AddonType> ADDON_TYPES = List.of( //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_AUTOMATION, "Automation"), //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_BINDING, "Bindings"), //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_MISC, "Misc"), //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_VOICE, "Voice"), //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_PERSISTENCE, "Persistence"), //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_TRANSFORMATION, "Transformations"), //
|
||||
new AddonType(FeatureInstaller.EXTENSION_TYPE_UI, "User Interfaces"));
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(KarafAddonService.class);
|
||||
|
||||
private final List<AddonType> typeList = new ArrayList<>(FeatureInstaller.EXTENSION_TYPES.size());
|
||||
|
||||
private final FeaturesService featuresService;
|
||||
private final FeatureInstaller featureInstaller;
|
||||
private final BindingInfoRegistry bindingInfoRegistry;
|
||||
|
||||
private final AddonInfoRegistry addonInfoRegistry;
|
||||
|
||||
@Activate
|
||||
public KarafAddonService(final @Reference FeatureInstaller featureInstaller,
|
||||
final @Reference FeaturesService featuresService,
|
||||
final @Reference BindingInfoRegistry bindingInfoRegistry) {
|
||||
final @Reference FeaturesService featuresService, @Reference AddonInfoRegistry addonInfoRegistry) {
|
||||
this.featureInstaller = featureInstaller;
|
||||
this.featuresService = featuresService;
|
||||
this.bindingInfoRegistry = bindingInfoRegistry;
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_AUTOMATION, "Automation"));
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_BINDING, "Bindings"));
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_MISC, "Misc"));
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_VOICE, "Voice"));
|
||||
if (!FeatureInstaller.SIMPLE_PACKAGE.equals(featureInstaller.getCurrentPackage())) {
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_PERSISTENCE, "Persistence"));
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_TRANSFORMATION, "Transformations"));
|
||||
typeList.add(new AddonType(FeatureInstaller.EXTENSION_TYPE_UI, "User Interfaces"));
|
||||
}
|
||||
this.addonInfoRegistry = addonInfoRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -85,10 +83,10 @@ public class KarafAddonService implements AddonService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Addon> getAddons(Locale locale) {
|
||||
public List<Addon> getAddons(@Nullable Locale locale) {
|
||||
try {
|
||||
return Arrays.stream(featuresService.listFeatures()).filter(this::isAddon).map(this::getAddon)
|
||||
.sorted(Comparator.comparing(Addon::getLabel)).collect(Collectors.toList());
|
||||
.sorted(Comparator.comparing(Addon::getLabel)).toList();
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception while retrieving features: {}", e.getMessage());
|
||||
return List.of();
|
||||
@ -101,7 +99,7 @@ public class KarafAddonService implements AddonService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Addon getAddon(String id, Locale locale) {
|
||||
public @Nullable Addon getAddon(String id, @Nullable Locale locale) {
|
||||
Feature feature;
|
||||
try {
|
||||
feature = featuresService.getFeature(FeatureInstaller.PREFIX + id);
|
||||
@ -112,62 +110,46 @@ public class KarafAddonService implements AddonService {
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable String getDefaultDocumentationLink(String type, String name) {
|
||||
return switch (type) {
|
||||
case FeatureInstaller.EXTENSION_TYPE_AUTOMATION -> "https://www.openhab.org/addons/automation/" + name
|
||||
+ "/";
|
||||
case FeatureInstaller.EXTENSION_TYPE_BINDING -> "https://www.openhab.org/addons/bindings/" + name + "/";
|
||||
case FeatureInstaller.EXTENSION_TYPE_PERSISTENCE -> "https://www.openhab.org/addons/persistence/" + name
|
||||
+ "/";
|
||||
case FeatureInstaller.EXTENSION_TYPE_TRANSFORMATION -> "https://www.openhab.org/addons/transformations/"
|
||||
+ name + "/";
|
||||
case FeatureInstaller.EXTENSION_TYPE_VOICE -> "https://www.openhab.org/addons/voice/" + name + "/";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private Addon getAddon(Feature feature) {
|
||||
String name = getName(feature.getName());
|
||||
String type = getType(feature.getName());
|
||||
String link = null;
|
||||
String configDescriptionURI = "";
|
||||
switch (type) {
|
||||
case FeatureInstaller.EXTENSION_TYPE_AUTOMATION:
|
||||
link = "https://www.openhab.org/addons/automation/" + name + "/";
|
||||
break;
|
||||
case FeatureInstaller.EXTENSION_TYPE_BINDING:
|
||||
link = "https://www.openhab.org/addons/bindings/" + name + "/";
|
||||
BindingInfo bindingInfo = bindingInfoRegistry.getBindingInfo(name);
|
||||
if (bindingInfo != null) {
|
||||
URI uri = bindingInfo.getConfigDescriptionURI();
|
||||
if (uri != null) {
|
||||
configDescriptionURI = uri.toString();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FeatureInstaller.EXTENSION_TYPE_MISC:
|
||||
// Not possible to define URL
|
||||
break;
|
||||
case FeatureInstaller.EXTENSION_TYPE_PERSISTENCE:
|
||||
link = "https://www.openhab.org/addons/persistence/" + name + "/";
|
||||
break;
|
||||
case FeatureInstaller.EXTENSION_TYPE_TRANSFORMATION:
|
||||
link = "https://www.openhab.org/addons/transformations/" + name + "/";
|
||||
break;
|
||||
case FeatureInstaller.EXTENSION_TYPE_UI:
|
||||
// Not possible to define URL
|
||||
break;
|
||||
case FeatureInstaller.EXTENSION_TYPE_VOICE:
|
||||
link = "https://www.openhab.org/addons/voice/" + name + "/";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
String id = type + Addon.ADDON_SEPARATOR + name;
|
||||
boolean isInstalled = featuresService.isInstalled(feature);
|
||||
|
||||
Addon.Builder addon = Addon.create(id).withContentType(ADDONS_CONTENT_TYPE).withType(type)
|
||||
.withVersion(feature.getVersion()).withAuthor(ADDONS_AUTHOR, true).withInstalled(isInstalled);
|
||||
|
||||
AddonInfo addonInfo = addonInfoRegistry.getAddonInfo(id);
|
||||
|
||||
if (isInstalled && addonInfo != null) {
|
||||
// only enrich if this add-on is installed, otherwise wrong data might be added
|
||||
addon = addon.withLabel(addonInfo.getName()).withDescription(addonInfo.getDescription())
|
||||
.withCountries(addonInfo.getCountries()).withLink(getDefaultDocumentationLink(type, name))
|
||||
.withConfigDescriptionURI(addonInfo.getConfigDescriptionURI());
|
||||
} else {
|
||||
addon = addon.withLabel(feature.getDescription()).withLink(getDefaultDocumentationLink(type, name));
|
||||
}
|
||||
|
||||
// for openHAB add-on bundles the package is the same as the bundle name
|
||||
List<String> packages = feature.getBundles().stream().filter(bundle -> !bundle.isDependency()).map(bundle -> {
|
||||
String location = bundle.getLocation();
|
||||
location = location.substring(0, location.lastIndexOf("/")); // strip version
|
||||
location = location.substring(location.lastIndexOf("/") + 1); // strip groupId and protocol
|
||||
return location;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
return Addon.create(type + "-" + name).withType(type).withLabel(feature.getDescription())
|
||||
.withVersion(feature.getVersion()).withContentType(ADDONS_CONTENTTYPE).withLink(link)
|
||||
.withLoggerPackages(packages).withAuthor(ADDONS_AUTHOR, true)
|
||||
.withConfigDescriptionURI(configDescriptionURI).withInstalled(featuresService.isInstalled(feature))
|
||||
.build();
|
||||
return addon.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AddonType> getTypes(Locale locale) {
|
||||
return typeList;
|
||||
public List<AddonType> getTypes(@Nullable Locale locale) {
|
||||
return ADDON_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -181,29 +163,19 @@ public class KarafAddonService implements AddonService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddonId(URI addonURI) {
|
||||
public @Nullable String getAddonId(URI addonURI) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String substringAfter(String str, String separator) {
|
||||
int index = str.indexOf(separator);
|
||||
return index == -1 ? "" : str.substring(index + separator.length());
|
||||
}
|
||||
|
||||
private String substringBefore(String str, String separator) {
|
||||
int index = str.indexOf(separator);
|
||||
private String getType(String name) {
|
||||
String str = name.startsWith(FeatureInstaller.PREFIX) ? name.substring(FeatureInstaller.PREFIX.length()) : name;
|
||||
int index = str.indexOf(Addon.ADDON_SEPARATOR);
|
||||
return index == -1 ? str : str.substring(0, index);
|
||||
}
|
||||
|
||||
private String getType(String name) {
|
||||
return substringBefore(
|
||||
name.startsWith(FeatureInstaller.PREFIX) ? name.substring(FeatureInstaller.PREFIX.length()) : name,
|
||||
"-");
|
||||
}
|
||||
|
||||
private String getName(String name) {
|
||||
return substringAfter(
|
||||
name.startsWith(FeatureInstaller.PREFIX) ? name.substring(FeatureInstaller.PREFIX.length()) : name,
|
||||
"-");
|
||||
String str = name.startsWith(FeatureInstaller.PREFIX) ? name.substring(FeatureInstaller.PREFIX.length()) : name;
|
||||
int index = str.indexOf(Addon.ADDON_SEPARATOR);
|
||||
return index == -1 ? "" : str.substring(index + Addon.ADDON_SEPARATOR.length());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="magic" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>Magic Binding</name>
|
||||
<description>This is the Magic binding for openHAB.</description>
|
||||
|
||||
</addon:addon>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="magic" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Magic Binding</name>
|
||||
<description>This is the Magic binding for openHAB.</description>
|
||||
|
||||
</binding:binding>
|
@ -27,12 +27,13 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
*/
|
||||
public class Addon {
|
||||
public static final Set<String> CODE_MATURITY_LEVELS = Set.of("alpha", "beta", "mature", "stable");
|
||||
public static final String ADDON_SEPARATOR = "-";
|
||||
|
||||
private final String id;
|
||||
private final String label;
|
||||
private final String version;
|
||||
private final @Nullable String maturity;
|
||||
private boolean compatible;
|
||||
private final boolean compatible;
|
||||
private final String contentType;
|
||||
private final @Nullable String link;
|
||||
private final String author;
|
||||
@ -43,7 +44,7 @@ public class Addon {
|
||||
private final @Nullable String detailedDescription;
|
||||
private final String configDescriptionURI;
|
||||
private final String keywords;
|
||||
private final String countries;
|
||||
private final List<String> countries;
|
||||
private final @Nullable String license;
|
||||
private final String connection;
|
||||
private final @Nullable String backgroundColor;
|
||||
@ -69,7 +70,7 @@ public class Addon {
|
||||
* @param detailedDescription the detailed description of the add-on (may be null)
|
||||
* @param configDescriptionURI the URI to the configuration description for this add-on
|
||||
* @param keywords the keywords for this add-on
|
||||
* @param countries a comma-separated list of ISO 3166 codes relevant to this add-on
|
||||
* @param countries a list of ISO 3166 codes relevant to this add-on
|
||||
* @param license the SPDX license identifier
|
||||
* @param connection a string describing the type of connection (local or cloud, push or pull...) this add-on uses,
|
||||
* if applicable.
|
||||
@ -81,7 +82,7 @@ public class Addon {
|
||||
private Addon(String id, String type, String label, String version, @Nullable String maturity, boolean compatible,
|
||||
String contentType, @Nullable String link, String author, boolean verifiedAuthor, boolean installed,
|
||||
@Nullable String description, @Nullable String detailedDescription, String configDescriptionURI,
|
||||
String keywords, String countries, @Nullable String license, String connection,
|
||||
String keywords, List<String> countries, @Nullable String license, String connection,
|
||||
@Nullable String backgroundColor, @Nullable String imageLink, @Nullable Map<String, Object> properties,
|
||||
List<String> loggerPackages) {
|
||||
this.id = id;
|
||||
@ -122,6 +123,10 @@ public class Addon {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getUID() {
|
||||
return type + ADDON_SEPARATOR + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The label of the add-on
|
||||
*/
|
||||
@ -207,9 +212,9 @@ public class Addon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma-separated list of ISO 3166 codes relevant to this add-on
|
||||
* A list of ISO 3166 codes relevant to this add-on
|
||||
*/
|
||||
public String getCountries() {
|
||||
public List<String> getCountries() {
|
||||
return countries;
|
||||
}
|
||||
|
||||
@ -221,7 +226,7 @@ public class Addon {
|
||||
}
|
||||
|
||||
/**
|
||||
* A string describing the type of connection (local or cloud, push or pull...) this add-on uses, if applicable.
|
||||
* A string describing the type of connection (local, cloud, cloudDiscovery) this add-on uses, if applicable.
|
||||
*/
|
||||
public String getConnection() {
|
||||
return connection;
|
||||
@ -289,7 +294,7 @@ public class Addon {
|
||||
private @Nullable String detailedDescription;
|
||||
private String configDescriptionURI = "";
|
||||
private String keywords = "";
|
||||
private String countries = "";
|
||||
private List<String> countries = List.of();
|
||||
private @Nullable String license;
|
||||
private String connection = "";
|
||||
private @Nullable String backgroundColor;
|
||||
@ -372,7 +377,7 @@ public class Addon {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCountries(String countries) {
|
||||
public Builder withCountries(List<String> countries) {
|
||||
this.countries = countries;
|
||||
return this;
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.openhab.core.internal.addon.AddonI18nUtil;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* This OSGi service could be used to localize the add-on info using the I18N mechanism of the openHAB
|
||||
* framework.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true, service = { AddonI18nLocalizationService.class })
|
||||
@NonNullByDefault
|
||||
public class AddonI18nLocalizationService {
|
||||
|
||||
private final AddonI18nUtil addonI18NUtil;
|
||||
|
||||
@Activate
|
||||
public AddonI18nLocalizationService(final @Reference TranslationProvider i18nProvider) {
|
||||
this.addonI18NUtil = new AddonI18nUtil(i18nProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Localizes an add-on info.
|
||||
*
|
||||
* @param bundle the bundle the i18n resources are located
|
||||
* @param addonInfo the add-on info that should be localized
|
||||
* @param locale the locale it should be localized to
|
||||
* @return a localized add-on info on success, a non-localized one on error (e.g. no translation is found).
|
||||
*/
|
||||
public AddonInfo createLocalizedAddonInfo(Bundle bundle, AddonInfo addonInfo, @Nullable Locale locale) {
|
||||
String addonInfoUID = addonInfo.getId();
|
||||
String name = addonI18NUtil.getName(bundle, addonInfoUID, addonInfo.getName(), locale);
|
||||
String description = addonI18NUtil.getDescription(bundle, addonInfoUID, addonInfo.getDescription(), locale);
|
||||
|
||||
return AddonInfo.builder(addonInfo).withName(name).withDescription(description).build();
|
||||
}
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.registry.Identifiable;
|
||||
|
||||
/**
|
||||
* The {@link AddonInfo} class contains general information about an add-on.
|
||||
* <p>
|
||||
* Any add-on information is provided by a {@link AddonInfoProvider} and can also be retrieved through the
|
||||
* {@link AddonInfoRegistry}.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Andre Fuechsel - Made author tag optional
|
||||
* @author Jan N. Klug - Refactored to cover all add-ons
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AddonInfo implements Identifiable<String> {
|
||||
private static final Set<String> SUPPORTED_ADDON_TYPES = Set.of("automation", "binding", "misc", "persistence",
|
||||
"transformation", "ui", "voice");
|
||||
|
||||
private final String id;
|
||||
private final String type;
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final @Nullable String author;
|
||||
private final @Nullable String connection;
|
||||
private final List<String> countries;
|
||||
private final @Nullable String configDescriptionURI;
|
||||
private final String serviceId;
|
||||
|
||||
private AddonInfo(String id, String type, String name, String description, @Nullable String author,
|
||||
@Nullable String connection, List<String> countries, @Nullable String configDescriptionURI,
|
||||
@Nullable String serviceId) throws IllegalArgumentException {
|
||||
// mandatory fields
|
||||
if (id.isBlank()) {
|
||||
throw new IllegalArgumentException("The ID must neither be null nor empty!");
|
||||
}
|
||||
if (!SUPPORTED_ADDON_TYPES.contains(type)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The type must be one of [" + String.join(", ", SUPPORTED_ADDON_TYPES) + "]");
|
||||
}
|
||||
if (name.isBlank()) {
|
||||
throw new IllegalArgumentException("The name must neither be null nor empty!");
|
||||
}
|
||||
if (description.isBlank()) {
|
||||
throw new IllegalArgumentException("The description must neither be null nor empty!");
|
||||
}
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
|
||||
// optional fields
|
||||
this.author = author;
|
||||
this.connection = connection;
|
||||
this.countries = countries;
|
||||
this.configDescriptionURI = configDescriptionURI;
|
||||
this.serviceId = Objects.requireNonNullElse(serviceId, type + "." + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unique identifier for the add-on (e.g. "binding-hue").
|
||||
*
|
||||
* @return an identifier for the add-on
|
||||
*/
|
||||
@Override
|
||||
public String getUID() {
|
||||
return type + Addon.ADDON_SEPARATOR + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id part of the UID
|
||||
*
|
||||
* @return the identifier
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable name for the add-on (e.g. "HUE Binding").
|
||||
*
|
||||
* @return a human-readable name for the add-on (neither null, nor empty)
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable description for the add-on
|
||||
* (e.g. "Discovers and controls HUE bulbs").
|
||||
*
|
||||
* @return a human-readable description for the add-on
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the author of the add-on (e.g. "Max Mustermann").
|
||||
*
|
||||
* @return the author of the add-on (could be null or empty)
|
||||
*/
|
||||
public @Nullable String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the link to a concrete {@link org.openhab.core.config.core.ConfigDescription}.
|
||||
*
|
||||
* @return the link to a concrete ConfigDescription (could be <code>null</code>>)
|
||||
*/
|
||||
public @Nullable String getConfigDescriptionURI() {
|
||||
return configDescriptionURI;
|
||||
}
|
||||
|
||||
public List<String> getCountries() {
|
||||
return countries;
|
||||
}
|
||||
|
||||
public static Builder builder(String id, String type) {
|
||||
return new Builder(id, type);
|
||||
}
|
||||
|
||||
public static Builder builder(AddonInfo addonInfo) {
|
||||
return new Builder(addonInfo);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final String id;
|
||||
private final String type;
|
||||
private String name = "";
|
||||
private String description = "";
|
||||
private @Nullable String author;
|
||||
private @Nullable String connection;
|
||||
private List<String> countries = List.of();
|
||||
private @Nullable String configDescriptionURI = "";
|
||||
private @Nullable String serviceId;
|
||||
|
||||
private Builder(String id, String type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private Builder(AddonInfo addonInfo) {
|
||||
this.id = addonInfo.id;
|
||||
this.type = addonInfo.type;
|
||||
this.name = addonInfo.name;
|
||||
this.description = addonInfo.description;
|
||||
this.author = addonInfo.author;
|
||||
this.connection = addonInfo.connection;
|
||||
this.countries = addonInfo.countries;
|
||||
this.configDescriptionURI = addonInfo.configDescriptionURI;
|
||||
this.serviceId = addonInfo.serviceId;
|
||||
}
|
||||
|
||||
public Builder withName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withAuthor(@Nullable String author) {
|
||||
this.author = author;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withConnection(@Nullable String connection) {
|
||||
this.connection = connection;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCountries(@Nullable String countries) {
|
||||
this.countries = List.of(Objects.requireNonNull(countries, "").split(","));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCountries(List<String> countries) {
|
||||
this.countries = countries;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withConfigDescriptionURI(@Nullable String configDescriptionURI) {
|
||||
this.configDescriptionURI = configDescriptionURI;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withServiceId(@Nullable String serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an {@link AddonInfo} from this builder
|
||||
*
|
||||
* @return the add-on info object
|
||||
* @throws IllegalArgumentException if any of the information in this builder is invalid
|
||||
*/
|
||||
public AddonInfo build() throws IllegalArgumentException {
|
||||
return new AddonInfo(id, type, name, description, author, connection, countries, configDescriptionURI,
|
||||
serviceId);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding;
|
||||
package org.openhab.core.addon;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
@ -19,16 +19,16 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfoProvider} is a service interface providing {@link BindingInfo} objects. All registered
|
||||
* {@link BindingInfoProvider} services are tracked by the {@link BindingInfoRegistry} and provided as one common
|
||||
* The {@link AddonInfoProvider} is a service interface providing {@link AddonInfo} objects. All registered
|
||||
* {@link AddonInfoProvider} services are tracked by the {@link AddonInfoRegistry} and provided as one common
|
||||
* collection.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
*
|
||||
* @see BindingInfoRegistry
|
||||
* @see AddonInfoRegistry
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface BindingInfoProvider {
|
||||
public interface AddonInfoProvider {
|
||||
|
||||
/**
|
||||
* Returns the binding information for the specified binding ID and locale (language),
|
||||
@ -39,7 +39,7 @@ public interface BindingInfoProvider {
|
||||
* @return a localized binding information object (could be null)
|
||||
*/
|
||||
@Nullable
|
||||
BindingInfo getBindingInfo(@Nullable String id, @Nullable Locale locale);
|
||||
AddonInfo getAddonInfo(@Nullable String id, @Nullable Locale locale);
|
||||
|
||||
/**
|
||||
* Returns all binding information in the specified locale (language) this provider contains.
|
||||
@ -48,5 +48,5 @@ public interface BindingInfoProvider {
|
||||
* @return a localized set of all binding information this provider contains
|
||||
* (could be empty)
|
||||
*/
|
||||
Set<BindingInfo> getBindingInfos(@Nullable Locale locale);
|
||||
Set<AddonInfo> getAddonInfos(@Nullable Locale locale);
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
|
||||
/**
|
||||
* The {@link AddonInfoRegistry} provides access to {@link AddonInfo} objects.
|
||||
* It tracks {@link AddonInfoProvider} <i>OSGi</i> services to collect all {@link AddonInfo} objects.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
* @author Michael Grammling - Initial contribution, added locale support
|
||||
*/
|
||||
@Component(immediate = true, service = AddonInfoRegistry.class)
|
||||
@NonNullByDefault
|
||||
public class AddonInfoRegistry {
|
||||
|
||||
private final Collection<AddonInfoProvider> addonInfoProviders = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
protected void addAddonInfoProvider(AddonInfoProvider addonInfoProvider) {
|
||||
addonInfoProviders.add(addonInfoProvider);
|
||||
}
|
||||
|
||||
protected void removeAddonInfoProvider(AddonInfoProvider addonInfoProvider) {
|
||||
addonInfoProviders.remove(addonInfoProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the add-on information for the specified add-on ID, or {@code null} if no add-on information could be
|
||||
* found.
|
||||
*
|
||||
* @param id the ID to be looked
|
||||
* @return a add-on information object (could be null)
|
||||
*/
|
||||
public @Nullable AddonInfo getAddonInfo(String id) {
|
||||
return getAddonInfo(id, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the add-on information for the specified add-on ID and locale (language),
|
||||
* or {@code null} if no add-on information could be found.
|
||||
*
|
||||
* @param id the ID to be looked for
|
||||
* @param locale the locale to be used for the add-on information (could be null)
|
||||
* @return a localized add-on information object (could be null)
|
||||
*/
|
||||
public @Nullable AddonInfo getAddonInfo(String id, @Nullable Locale locale) {
|
||||
return addonInfoProviders.stream().map(p -> p.getAddonInfo(id, locale)).filter(Objects::nonNull).findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all add-on information this registry contains.
|
||||
*
|
||||
* @return a set of all add-on information this registry contains (not null, could be empty)
|
||||
*/
|
||||
public Set<AddonInfo> getAddonInfos() {
|
||||
return getAddonInfos(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all add-on information in the specified locale (language) this registry contains.
|
||||
*
|
||||
* @param locale the locale to be used for the add-on information (could be null)
|
||||
* @return a localized set of all add-on information this registry contains
|
||||
* (not null, could be empty)
|
||||
*/
|
||||
public Set<AddonInfo> getAddonInfos(@Nullable Locale locale) {
|
||||
return addonInfoProviders.stream().map(provider -> provider.getAddonInfos(locale)).flatMap(Set::stream)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
}
|
@ -55,7 +55,7 @@ public class AddonType {
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + id.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -70,14 +70,6 @@ public class AddonType {
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AddonType other = (AddonType) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return id.equals(((AddonType) obj).id);
|
||||
}
|
||||
}
|
||||
|
@ -1,137 +0,0 @@
|
||||
/**
|
||||
* 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.binding;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.common.registry.Identifiable;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfo} class contains general information about a binding.
|
||||
* <p>
|
||||
* Any binding information are provided by a {@link BindingInfoProvider} and can also be retrieved through the
|
||||
* {@link BindingInfoRegistry}.
|
||||
* <p>
|
||||
* <b>Hint:</b> This class is immutable.
|
||||
*
|
||||
* @author Michael Grammling - Initial contribution
|
||||
* @author Andre Fuechsel - Made author tag optional
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfo implements Identifiable<String> {
|
||||
|
||||
/**
|
||||
* The default service ID prefix.
|
||||
*/
|
||||
public static final String DEFAULT_SERVICE_ID_PREFIX = "binding.";
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private @Nullable String description;
|
||||
private @Nullable String author;
|
||||
private @Nullable URI configDescriptionURI;
|
||||
private String serviceId;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this class with the specified parameters.
|
||||
*
|
||||
* @param id the identifier for the binding (must neither be null, nor empty)
|
||||
* @param name a human readable name for the binding (must neither be null, nor empty)
|
||||
* @param description a human readable description for the binding (could be null or empty)
|
||||
* @param author the author of the binding (could be null or empty)
|
||||
* @param serviceId the service id of the main service of the binding (can be null)
|
||||
* @param configDescriptionURI the link to a concrete ConfigDescription (could be null)
|
||||
* @throws IllegalArgumentException if the identifier or the name are null or empty
|
||||
*/
|
||||
public BindingInfo(String id, String name, @Nullable String description, @Nullable String author,
|
||||
@Nullable String serviceId, @Nullable URI configDescriptionURI) throws IllegalArgumentException {
|
||||
if ((id == null) || (id.isEmpty())) {
|
||||
throw new IllegalArgumentException("The ID must neither be null nor empty!");
|
||||
}
|
||||
|
||||
if ((name == null) || (name.isEmpty())) {
|
||||
throw new IllegalArgumentException("The name must neither be null nor empty!");
|
||||
}
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.author = author;
|
||||
this.serviceId = serviceId != null ? serviceId : DEFAULT_SERVICE_ID_PREFIX + id;
|
||||
this.configDescriptionURI = configDescriptionURI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an identifier for the binding (e.g. "hue").
|
||||
*
|
||||
* @return an identifier for the binding (neither null, nor empty)
|
||||
*/
|
||||
@Override
|
||||
public String getUID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable name for the binding (e.g. "HUE Binding").
|
||||
*
|
||||
* @return a human readable name for the binding (neither null, nor empty)
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable description for the binding
|
||||
* (e.g. "Discovers and controls HUE bulbs").
|
||||
*
|
||||
* @return a human readable description for the binding (could be null or empty)
|
||||
*/
|
||||
public @Nullable String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the author of the binding (e.g. "Max Mustermann").
|
||||
*
|
||||
* @return the author of the binding (could be null or empty)
|
||||
*/
|
||||
public @Nullable String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the service ID of the bindings main service, that can be configured.
|
||||
*
|
||||
* @return service ID
|
||||
*/
|
||||
public String getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the link to a concrete {@link ConfigDescription}.
|
||||
*
|
||||
* @return the link to a concrete ConfigDescription (could be null)
|
||||
*/
|
||||
public @Nullable URI getConfigDescriptionURI() {
|
||||
return configDescriptionURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BindingInfo [id=" + id + ", name=" + name + ", description=" + description + ", author=" + author
|
||||
+ ", configDescriptionURI=" + configDescriptionURI + "]";
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/**
|
||||
* 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.binding;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.osgi.service.component.annotations.ReferenceCardinality;
|
||||
import org.osgi.service.component.annotations.ReferencePolicy;
|
||||
|
||||
/**
|
||||
* The {@link BindingInfoRegistry} provides access to {@link BindingInfo} objects.
|
||||
* It tracks {@link BindingInfoProvider} <i>OSGi</i> services to collect all {@link BindingInfo} objects.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
* @author Michael Grammling - Initial contribution, added locale support
|
||||
*/
|
||||
@Component(immediate = true, service = BindingInfoRegistry.class)
|
||||
@NonNullByDefault
|
||||
public class BindingInfoRegistry {
|
||||
|
||||
private final Collection<BindingInfoProvider> bindingInfoProviders = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
protected void addBindingInfoProvider(BindingInfoProvider bindingInfoProvider) {
|
||||
if (bindingInfoProvider != null) {
|
||||
bindingInfoProviders.add(bindingInfoProvider);
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeBindingInfoProvider(BindingInfoProvider bindingInfoProvider) {
|
||||
if (bindingInfoProvider != null) {
|
||||
bindingInfoProviders.remove(bindingInfoProvider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding information for the specified binding ID, or {@code null} if no binding information could be
|
||||
* found.
|
||||
*
|
||||
* @param id the ID to be looked for (could be null or empty)
|
||||
* @return a binding information object (could be null)
|
||||
*/
|
||||
public @Nullable BindingInfo getBindingInfo(@Nullable String id) {
|
||||
return getBindingInfo(id, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding information for the specified binding ID and locale (language),
|
||||
* or {@code null} if no binding information could be found.
|
||||
*
|
||||
* @param id the ID to be looked for (could be null or empty)
|
||||
* @param locale the locale to be used for the binding information (could be null)
|
||||
* @return a localized binding information object (could be null)
|
||||
*/
|
||||
public @Nullable BindingInfo getBindingInfo(@Nullable String id, @Nullable Locale locale) {
|
||||
for (BindingInfoProvider bindingInfoProvider : bindingInfoProviders) {
|
||||
BindingInfo bindingInfo = bindingInfoProvider.getBindingInfo(id, locale);
|
||||
if (bindingInfo != null) {
|
||||
return bindingInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all binding information this registry contains.
|
||||
*
|
||||
* @return a set of all binding information this registry contains (not null, could be empty)
|
||||
*/
|
||||
public Set<BindingInfo> getBindingInfos() {
|
||||
return getBindingInfos(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all binding information in the specified locale (language) this registry contains.
|
||||
*
|
||||
* @param locale the locale to be used for the binding information (could be null)
|
||||
* @return a localized set of all binding information this registry contains
|
||||
* (not null, could be empty)
|
||||
*/
|
||||
public Set<BindingInfo> getBindingInfos(@Nullable Locale locale) {
|
||||
Set<BindingInfo> allBindingInfos = new LinkedHashSet<>(bindingInfoProviders.size());
|
||||
for (BindingInfoProvider bindingInfoProvider : bindingInfoProviders) {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoProvider.getBindingInfos(locale);
|
||||
allBindingInfos.addAll(bindingInfos);
|
||||
}
|
||||
return Collections.unmodifiableSet(allBindingInfos);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/**
|
||||
* 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.binding.dto;
|
||||
|
||||
/**
|
||||
* This is a data transfer object that is used to serialize binding info objects.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
*/
|
||||
public class BindingInfoDTO {
|
||||
|
||||
public String author;
|
||||
public String description;
|
||||
public String id;
|
||||
public String name;
|
||||
public String configDescriptionURI;
|
||||
|
||||
public BindingInfoDTO() {
|
||||
}
|
||||
|
||||
public BindingInfoDTO(String id, String name, String author, String description, String configDescriptionURI) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.author = author;
|
||||
this.description = description;
|
||||
this.configDescriptionURI = configDescriptionURI;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
/**
|
||||
* 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.binding.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.internal.i18n.BindingI18nUtil;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* This OSGi service could be used to localize the binding info using the I18N mechanism of the openHAB
|
||||
* framework.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true, service = { BindingI18nLocalizationService.class })
|
||||
@NonNullByDefault
|
||||
public class BindingI18nLocalizationService {
|
||||
|
||||
private final BindingI18nUtil bindingI18nUtil;
|
||||
|
||||
@Activate
|
||||
public BindingI18nLocalizationService(final @Reference TranslationProvider i18nProvider) {
|
||||
this.bindingI18nUtil = new BindingI18nUtil(i18nProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Localizes a binding info.
|
||||
*
|
||||
* @param bundle the bundle the i18n resources are located
|
||||
* @param bindingInfo the binding info that should be localized
|
||||
* @param locale the locale it should be localized to
|
||||
* @return a localized binding info on success, a non-localized one on error (e.g. no translation is found).
|
||||
*/
|
||||
public BindingInfo createLocalizedBindingInfo(Bundle bundle, BindingInfo bindingInfo, @Nullable Locale locale) {
|
||||
String bindingInfoUID = bindingInfo.getUID();
|
||||
String name = bindingI18nUtil.getName(bundle, bindingInfoUID, bindingInfo.getName(), locale);
|
||||
String description = bindingI18nUtil.getDescription(bundle, bindingInfoUID, bindingInfo.getDescription(),
|
||||
locale);
|
||||
|
||||
return new BindingInfo(bindingInfoUID, name == null ? bindingInfo.getName() : name,
|
||||
description == null ? bindingInfo.getDescription() : description, bindingInfo.getAuthor(),
|
||||
bindingInfo.getServiceId(), bindingInfo.getConfigDescriptionURI());
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.internal.i18n;
|
||||
package org.openhab.core.internal.addon;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@ -21,18 +21,18 @@ import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
||||
/**
|
||||
* The {@link BindingI18nUtil} uses the {@link TranslationProvider} to resolve the
|
||||
* The {@link AddonI18nUtil} uses the {@link TranslationProvider} to resolve the
|
||||
* localized texts. It automatically infers the key if the default text is not a
|
||||
* constant.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingI18nUtil {
|
||||
public class AddonI18nUtil {
|
||||
|
||||
private final TranslationProvider i18nProvider;
|
||||
|
||||
public BindingI18nUtil(TranslationProvider i18nProvider) {
|
||||
public AddonI18nUtil(TranslationProvider i18nProvider) {
|
||||
this.i18nProvider = i18nProvider;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
<modules>
|
||||
<module>org.openhab.core.addon.marketplace</module>
|
||||
<module>org.openhab.core.addon.marketplace.karaf</module>
|
||||
<module>org.openhab.core.addon.xml</module>
|
||||
<module>org.openhab.core.auth.jaas</module>
|
||||
<module>org.openhab.core.auth.oauth2client</module>
|
||||
<module>org.openhab.core.automation</module>
|
||||
@ -38,7 +39,6 @@
|
||||
<module>org.openhab.core.config.xml</module>
|
||||
<module>org.openhab.core</module>
|
||||
<module>org.openhab.core.audio</module>
|
||||
<module>org.openhab.core.binding.xml</module>
|
||||
<module>org.openhab.core.ephemeris</module>
|
||||
<module>org.openhab.core.addon.sample</module>
|
||||
<module>org.openhab.core.id</module>
|
||||
|
@ -47,7 +47,7 @@
|
||||
<bundle start-level="75">mvn:org.openhab.core.bundles/org.openhab.core.config.xml/${project.version}</bundle>
|
||||
<bundle>mvn:org.openhab.core.bundles/org.openhab.core/${project.version}</bundle>
|
||||
<feature dependency="true">openhab-core-storage-json</feature>
|
||||
<bundle>mvn:org.openhab.core.bundles/org.openhab.core.binding.xml/${project.version}</bundle>
|
||||
<bundle>mvn:org.openhab.core.bundles/org.openhab.core.addon.xml/${project.version}</bundle>
|
||||
<bundle>mvn:org.openhab.core.bundles/org.openhab.core.ephemeris/${project.version}</bundle>
|
||||
<bundle>mvn:org.openhab.core.bundles/org.openhab.core.id/${project.version}</bundle>
|
||||
<bundle>mvn:org.openhab.core.bundles/org.openhab.core.persistence/${project.version}</bundle>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.core.binding.xml.tests</name>
|
||||
<name>org.openhab.core.addon.xml.tests</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
@ -1,13 +1,13 @@
|
||||
-include: ../itest-common.bndrun
|
||||
|
||||
Bundle-SymbolicName: ${project.artifactId}
|
||||
Fragment-Host: org.openhab.core.binding.xml
|
||||
Fragment-Host: org.openhab.core.addon.xml
|
||||
|
||||
-runblacklist: \
|
||||
bnd.identity;id='org.osgi.service.cm'
|
||||
|
||||
-runrequires: \
|
||||
bnd.identity;id='org.openhab.core.binding.xml.tests'
|
||||
bnd.identity;id='org.openhab.core.addon.xml.tests'
|
||||
|
||||
#
|
||||
# done
|
||||
@ -52,10 +52,10 @@ Fragment-Host: org.openhab.core.binding.xml
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.binding.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.binding.xml.tests;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.addon.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.addon.xml.tests;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)'
|
@ -9,8 +9,8 @@
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.core.binding.xml.tests</artifactId>
|
||||
<artifactId>org.openhab.core.addon.xml.tests</artifactId>
|
||||
|
||||
<name>openHAB Core :: Integration Tests :: Binding XML Tests</name>
|
||||
<name>openHAB Core :: Integration Tests :: Add-on XML Tests</name>
|
||||
|
||||
</project>
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.xml.test;
|
||||
package org.openhab.core.addon.xml.test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@ -23,8 +23,8 @@ import java.util.Set;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.BindingInfoRegistry;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.addon.AddonInfoRegistry;
|
||||
import org.openhab.core.i18n.LocaleProvider;
|
||||
import org.openhab.core.internal.i18n.I18nProviderImpl;
|
||||
import org.openhab.core.test.java.JavaOSGiTest;
|
||||
@ -35,38 +35,38 @@ import org.osgi.service.cm.ConfigurationAdmin;
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfoI18nTest extends JavaOSGiTest {
|
||||
public class AddonInfoI18nTest extends JavaOSGiTest {
|
||||
|
||||
private static final String TEST_BUNDLE_NAME = "acmeweather.bundle";
|
||||
|
||||
private @NonNullByDefault({}) BindingInfoRegistry bindingInfoRegistry;
|
||||
private @NonNullByDefault({}) BindingInstaller bindingInstaller;
|
||||
private @NonNullByDefault({}) AddonInfoRegistry addonInfoRegistry;
|
||||
private @NonNullByDefault({}) AddonInstaller addonInstaller;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
bindingInfoRegistry = getService(BindingInfoRegistry.class);
|
||||
assertThat(bindingInfoRegistry, is(notNullValue()));
|
||||
bindingInstaller = new BindingInstaller(this::waitForAssert, bindingInfoRegistry, bundleContext);
|
||||
addonInfoRegistry = getService(AddonInfoRegistry.class);
|
||||
assertThat(addonInfoRegistry, is(notNullValue()));
|
||||
addonInstaller = new AddonInstaller(this::waitForAssert, addonInfoRegistry, bundleContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertBindingInfosWereLocalizedInGerman() throws Exception {
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(Locale.GERMAN);
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
public void assertAddonInfosWereLocalizedInGerman() throws Exception {
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<AddonInfo> addonInfos = addonInfoRegistry.getAddonInfos(Locale.GERMAN);
|
||||
AddonInfo addonInfo = addonInfos.iterator().next();
|
||||
|
||||
assertThat(bindingInfo, is(notNullValue()));
|
||||
assertThat(bindingInfo.getName(), is("ACME Wetter Binding"));
|
||||
assertThat(bindingInfo.getDescription(), is(
|
||||
assertThat(addonInfo, is(notNullValue()));
|
||||
assertThat(addonInfo.getName(), is("ACME Wetter Binding"));
|
||||
assertThat(addonInfo.getDescription(), is(
|
||||
"Das ACME Wetter Binding stellt verschiedene Wetterdaten wie die Temperatur, die Luftfeuchtigkeit und den Luftdruck für konfigurierbare Orte vom ACME Wetterdienst bereit"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertBindingInfosWereLocalizedInDutch() throws Exception {
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(new Locale("nl"));
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
public void assertAddonInfosWereLocalizedInDutch() throws Exception {
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<AddonInfo> bindingInfos = addonInfoRegistry.getAddonInfos(new Locale("nl"));
|
||||
AddonInfo bindingInfo = bindingInfos.iterator().next();
|
||||
|
||||
assertThat(bindingInfo, is(notNullValue()));
|
||||
assertThat(bindingInfo.getName(), is("ACME Weer Binding"));
|
||||
@ -76,10 +76,10 @@ public class BindingInfoI18nTest extends JavaOSGiTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertUsingOriginalBindingInfosIfProvidedLocaleIsNotSupported() throws Exception {
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(Locale.FRENCH);
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
public void assertUsingOriginalAddonInfosIfProvidedLocaleIsNotSupported() throws Exception {
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<AddonInfo> bindingInfos = addonInfoRegistry.getAddonInfos(Locale.FRENCH);
|
||||
AddonInfo bindingInfo = bindingInfos.iterator().next();
|
||||
|
||||
assertThat(bindingInfo, is(notNullValue()));
|
||||
assertThat(bindingInfo.getName(), is("ACME Weather Binding"));
|
||||
@ -113,10 +113,10 @@ public class BindingInfoI18nTest extends JavaOSGiTest {
|
||||
|
||||
waitForAssert(() -> assertThat(localeProvider.getLocale().toString(), is("de_DE")));
|
||||
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
// use default locale
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos(null);
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
Set<AddonInfo> bindingInfos = addonInfoRegistry.getAddonInfos(null);
|
||||
AddonInfo bindingInfo = bindingInfos.iterator().next();
|
||||
assertThat(bindingInfo, is(notNullValue()));
|
||||
assertThat(bindingInfo.getName(), is("ACME Wetter Binding"));
|
||||
assertThat(bindingInfo.getDescription(), is(
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.xml.test;
|
||||
package org.openhab.core.addon.xml.test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@ -24,8 +24,8 @@ import java.util.stream.Collectors;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.BindingInfoRegistry;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.addon.AddonInfoRegistry;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ConfigDescriptionRegistry;
|
||||
@ -36,60 +36,63 @@ import org.openhab.core.test.java.JavaOSGiTest;
|
||||
* @author Wouter Born - Migrate tests from Groovy to Java
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInfoTest extends JavaOSGiTest {
|
||||
public class AddonInfoTest extends JavaOSGiTest {
|
||||
|
||||
private static final String TEST_BUNDLE_NAME = "BundleInfoTest.bundle";
|
||||
private static final String TEST_BUNDLE_NAME2 = "BundleInfoTestNoAuthor.bundle";
|
||||
|
||||
private @NonNullByDefault({}) BindingInfoRegistry bindingInfoRegistry;
|
||||
private @NonNullByDefault({}) AddonInfoRegistry addonInfoRegistry;
|
||||
private @NonNullByDefault({}) ConfigDescriptionRegistry configDescriptionRegistry;
|
||||
private @NonNullByDefault({}) BindingInstaller bindingInstaller;
|
||||
private @NonNullByDefault({}) AddonInstaller addonInstaller;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
bindingInfoRegistry = getService(BindingInfoRegistry.class);
|
||||
assertThat(bindingInfoRegistry, is(notNullValue()));
|
||||
addonInfoRegistry = getService(AddonInfoRegistry.class);
|
||||
assertThat(addonInfoRegistry, is(notNullValue()));
|
||||
configDescriptionRegistry = getService(ConfigDescriptionRegistry.class);
|
||||
assertThat(configDescriptionRegistry, is(notNullValue()));
|
||||
bindingInstaller = new BindingInstaller(this::waitForAssert, bindingInfoRegistry, bundleContext);
|
||||
addonInstaller = new AddonInstaller(this::waitForAssert, addonInfoRegistry, bundleContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatBindingInfoIsReadProperly() throws Exception {
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
assertThat(bindingInfo.getUID(), is("hue"));
|
||||
assertThat(bindingInfo.getConfigDescriptionURI(), is(URI.create("binding:hue")));
|
||||
assertThat(bindingInfo.getDescription(),
|
||||
public void assertThatAddonInfoIsReadProperly() throws Exception {
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<AddonInfo> addonInfos = addonInfoRegistry.getAddonInfos();
|
||||
AddonInfo addonInfo = addonInfos.iterator().next();
|
||||
assertThat(addonInfo.getId(), is("hue"));
|
||||
assertThat(addonInfo.getUID(), is("binding-hue"));
|
||||
assertThat(addonInfo.getConfigDescriptionURI(), is("binding:hue"));
|
||||
assertThat(addonInfo.getDescription(),
|
||||
is("The hue Binding integrates the Philips hue system. It allows to control hue lights."));
|
||||
assertThat(bindingInfo.getName(), is("hue Binding"));
|
||||
assertThat(bindingInfo.getAuthor(), is("Deutsche Telekom AG"));
|
||||
assertThat(addonInfo.getName(), is("hue Binding"));
|
||||
assertThat(addonInfo.getAuthor(), is("Deutsche Telekom AG"));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatBindingInfoWithoutAuthorIsReadProperly() throws Exception {
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME2, () -> {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
assertThat(bindingInfo.getUID(), is("hue"));
|
||||
assertThat(bindingInfo.getConfigDescriptionURI(), is(URI.create("binding:hue")));
|
||||
assertThat(bindingInfo.getDescription(),
|
||||
public void assertThatAddonInfoWithoutAuthorIsReadProperly() throws Exception {
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME2, () -> {
|
||||
Set<AddonInfo> addonInfos = addonInfoRegistry.getAddonInfos();
|
||||
AddonInfo addonInfo = addonInfos.iterator().next();
|
||||
assertThat(addonInfo.getId(), is("hue"));
|
||||
assertThat(addonInfo.getUID(), is("binding-hue"));
|
||||
assertThat(addonInfo.getConfigDescriptionURI(), is("foo:bar"));
|
||||
assertThat(addonInfo.getDescription(),
|
||||
is("The hue Binding integrates the Philips hue system. It allows to control hue lights."));
|
||||
assertThat(bindingInfo.getName(), is("hue Binding"));
|
||||
assertThat(bindingInfo.getAuthor(), is((String) null));
|
||||
assertThat(addonInfo.getName(), is("hue Binding"));
|
||||
assertThat(addonInfo.getAuthor(), is((String) null));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void assertThatConfigWithOptionsAndFilterAreProperlyRead() throws Exception {
|
||||
bindingInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<BindingInfo> bindingInfos = bindingInfoRegistry.getBindingInfos();
|
||||
BindingInfo bindingInfo = bindingInfos.iterator().next();
|
||||
addonInstaller.exec(TEST_BUNDLE_NAME, () -> {
|
||||
Set<AddonInfo> bindingInfos = addonInfoRegistry.getAddonInfos();
|
||||
AddonInfo bindingInfo = bindingInfos.iterator().next();
|
||||
|
||||
URI configDescriptionURI = Objects.requireNonNull(bindingInfo.getConfigDescriptionURI());
|
||||
ConfigDescription configDescription = configDescriptionRegistry.getConfigDescription(configDescriptionURI);
|
||||
String configDescriptionURI = Objects.requireNonNull(bindingInfo.getConfigDescriptionURI());
|
||||
ConfigDescription configDescription = configDescriptionRegistry
|
||||
.getConfigDescription(URI.create(configDescriptionURI));
|
||||
List<ConfigDescriptionParameter> parameters = configDescription.getParameters();
|
||||
assertThat(parameters.size(), is(2));
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.binding.xml.test;
|
||||
package org.openhab.core.addon.xml.test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@ -18,7 +18,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.binding.BindingInfoRegistry;
|
||||
import org.openhab.core.addon.AddonInfoRegistry;
|
||||
import org.openhab.core.test.BundleCloseable;
|
||||
import org.openhab.core.test.SyntheticBundleInstaller;
|
||||
import org.osgi.framework.BundleContext;
|
||||
@ -27,36 +27,35 @@ import org.osgi.framework.BundleContext;
|
||||
* @author Markus Rathgeb - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BindingInstaller {
|
||||
public class AddonInstaller {
|
||||
|
||||
private final Consumer<Runnable> waitForAssert;
|
||||
private final BindingInfoRegistry bindingInfoRegistry;
|
||||
private final AddonInfoRegistry addonInfoRegistry;
|
||||
private final BundleContext bc;
|
||||
|
||||
public BindingInstaller(Consumer<Runnable> waitForAssert, BindingInfoRegistry bindingInfoRegistry,
|
||||
BundleContext bc) {
|
||||
public AddonInstaller(Consumer<Runnable> waitForAssert, AddonInfoRegistry addonInfoRegistry, BundleContext bc) {
|
||||
this.waitForAssert = waitForAssert;
|
||||
this.bindingInfoRegistry = bindingInfoRegistry;
|
||||
this.addonInfoRegistry = addonInfoRegistry;
|
||||
this.bc = bc;
|
||||
}
|
||||
|
||||
public void exec(final String bundleName, final Runnable func) throws Exception {
|
||||
// Save the number of currently installed bundles.
|
||||
final int initialNumberOfBindingInfos = bindingInfoRegistry.getBindingInfos().size();
|
||||
final int initialNumberOfBindingInfos = addonInfoRegistry.getAddonInfos().size();
|
||||
|
||||
// install test bundle
|
||||
try (BundleCloseable bundle = new BundleCloseable(SyntheticBundleInstaller.install(bc, bundleName))) {
|
||||
assertThat(bundle, is(notNullValue()));
|
||||
|
||||
// Wait for correctly installed bundle.
|
||||
waitForAssert.accept(() -> assertThat(bindingInfoRegistry.getBindingInfos().size(),
|
||||
is(initialNumberOfBindingInfos + 1)));
|
||||
waitForAssert.accept(
|
||||
() -> assertThat(addonInfoRegistry.getAddonInfos().size(), is(initialNumberOfBindingInfos + 1)));
|
||||
|
||||
func.run();
|
||||
}
|
||||
|
||||
// Wait for correctly uninstalled bundle.
|
||||
waitForAssert.accept(
|
||||
() -> assertThat(bindingInfoRegistry.getBindingInfos().size(), is(initialNumberOfBindingInfos)));
|
||||
waitForAssert
|
||||
.accept(() -> assertThat(addonInfoRegistry.getAddonInfos().size(), is(initialNumberOfBindingInfos)));
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd" id="hue">
|
||||
<addon:addon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd" id="hue">
|
||||
|
||||
<type>binding</type>
|
||||
<name>hue Binding</name>
|
||||
<description>The hue Binding integrates the Philips hue system. It
|
||||
allows to control hue lights.</description>
|
||||
@ -29,4 +30,4 @@
|
||||
|
||||
</config-description>
|
||||
|
||||
</binding:binding>
|
||||
</addon:addon>
|
@ -1,15 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd" id="hue">
|
||||
<addon:addon xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd" id="hue">
|
||||
|
||||
<type>binding</type>
|
||||
<name>hue Binding</name>
|
||||
<description>The hue Binding integrates the Philips hue system. It
|
||||
allows to control hue lights.</description>
|
||||
|
||||
|
||||
<!-- Dummy config -->
|
||||
<config-description>
|
||||
<config-description uri="foo:bar">
|
||||
|
||||
<parameter name="list" type="text" multiple="true" min="2" max="3">
|
||||
<options>
|
||||
@ -29,4 +30,4 @@
|
||||
|
||||
</config-description>
|
||||
|
||||
</binding:binding>
|
||||
</addon:addon>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="acmeweather" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>ACME Weather Binding</name>
|
||||
<description>The ACME Weather Binding requests the ACME Weather Service to show the current temperature, humidity and
|
||||
pressure.</description>
|
||||
|
||||
</addon:addon>
|
@ -56,10 +56,10 @@ Fragment-Host: org.openhab.core.auth.oauth2client
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.auth.oauth2client;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.auth.oauth2client.tests;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.io.console;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.io.net;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)'
|
||||
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="acmeweather" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>ACME Weather Binding</name>
|
||||
<description>The ACME Weather Binding requests the ACME Weather Service to show the current temperature, humidity and
|
||||
pressure.</description>
|
||||
|
||||
</binding:binding>
|
@ -53,6 +53,7 @@ Fragment-Host: org.openhab.core.config.discovery.mdns
|
||||
javax.jmdns;version='[3.5.8,3.5.9)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.discovery;version='[4.0.0,4.0.1)',\
|
||||
@ -61,5 +62,4 @@ Fragment-Host: org.openhab.core.config.discovery.mdns
|
||||
org.openhab.core.io.console;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.io.transport.mdns;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)'
|
||||
|
@ -56,6 +56,7 @@ Fragment-Host: org.openhab.core.config.discovery
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.discovery;version='[4.0.0,4.0.1)',\
|
||||
@ -64,5 +65,4 @@ Fragment-Host: org.openhab.core.config.discovery
|
||||
org.openhab.core.io.console;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing.xml;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.thing.xml;version='[4.0.0,4.0.1)'
|
||||
|
@ -53,6 +53,7 @@ Fragment-Host: org.openhab.core.config.discovery.usbserial.linuxsysfs
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.discovery;version='[4.0.0,4.0.1)',\
|
||||
@ -61,5 +62,4 @@ Fragment-Host: org.openhab.core.config.discovery.usbserial.linuxsysfs
|
||||
org.openhab.core.config.discovery.usbserial.linuxsysfs.tests;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.io.console;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)'
|
||||
|
@ -62,6 +62,7 @@ Provide-Capability: \
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.discovery;version='[4.0.0,4.0.1)',\
|
||||
@ -69,5 +70,4 @@ Provide-Capability: \
|
||||
org.openhab.core.config.discovery.usbserial.tests;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.io.console;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)'
|
||||
|
@ -48,8 +48,8 @@ Fragment-Host: org.openhab.core.config.dispatch
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.dispatch;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.dispatch.tests;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)'
|
||||
|
@ -45,6 +45,7 @@ Fragment-Host: org.openhab.core.io.rest.core
|
||||
org.glassfish.hk2.external.javax.inject;version='[2.4.0,2.4.1)',\
|
||||
tech.units.indriya;version='[2.1.2,2.1.3)',\
|
||||
uom-lib-common;version='[2.1.0,2.1.1)',\
|
||||
com.fasterxml.woodstox.woodstox-core;version='[6.2.6,6.2.7)',\
|
||||
org.apache.cxf.cxf-core;version='[3.4.5,3.4.6)',\
|
||||
org.apache.cxf.cxf-rt-frontend-jaxrs;version='[3.4.5,3.4.6)',\
|
||||
org.apache.cxf.cxf-rt-rs-client;version='[3.4.5,3.4.6)',\
|
||||
@ -84,9 +85,11 @@ Fragment-Host: org.openhab.core.io.rest.core
|
||||
org.ops4j.pax.web.pax-web-spi;version='[7.3.25,7.3.26)',\
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
junit-jupiter-params;version='[5.8.1,5.8.2)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
junit-jupiter-params;version='[5.8.1,5.8.2)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.discovery;version='[4.0.0,4.0.1)',\
|
||||
@ -98,7 +101,4 @@ Fragment-Host: org.openhab.core.io.rest.core
|
||||
org.openhab.core.semantics;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
com.fasterxml.woodstox.woodstox-core;version='[6.4.0,6.4.1)'
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)'
|
||||
|
@ -75,6 +75,18 @@ Fragment-Host: org.openhab.core.model.core
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.apache.log4j;version='[1.2.19,1.2.20)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.audio;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.automation;version='[4.0.0,4.0.1)',\
|
||||
@ -99,15 +111,4 @@ Fragment-Host: org.openhab.core.model.core
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)'
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)'
|
||||
|
@ -72,6 +72,18 @@ Fragment-Host: org.openhab.core.model.item
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.apache.log4j;version='[1.2.19,1.2.20)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.audio;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.automation;version='[4.0.0,4.0.1)',\
|
||||
@ -97,15 +109,4 @@ Fragment-Host: org.openhab.core.model.item
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)'
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)'
|
||||
|
@ -73,6 +73,18 @@ Fragment-Host: org.openhab.core.model.rule.runtime
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.apache.log4j;version='[1.2.19,1.2.20)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.audio;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.automation;version='[4.0.0,4.0.1)',\
|
||||
@ -98,16 +110,5 @@ Fragment-Host: org.openhab.core.model.rule.runtime
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)'
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)'
|
||||
-runblacklist: bnd.identity;id='jakarta.activation-api'
|
||||
|
@ -75,6 +75,18 @@ Fragment-Host: org.openhab.core.model.script
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.apache.log4j;version='[1.2.19,1.2.20)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.audio;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.automation;version='[4.0.0,4.0.1)',\
|
||||
@ -99,15 +111,4 @@ Fragment-Host: org.openhab.core.model.script
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)'
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)'
|
||||
|
@ -81,6 +81,18 @@ Fragment-Host: org.openhab.core.model.thing
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.apache.log4j;version='[1.2.19,1.2.20)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.audio;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.automation;version='[4.0.0,4.0.1)',\
|
||||
@ -110,15 +122,4 @@ Fragment-Host: org.openhab.core.model.thing
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.transform;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
io.github.classgraph;version='[4.8.149,4.8.150)',\
|
||||
org.eclipse.equinox.common;version='[3.16.200,3.16.201)',\
|
||||
org.eclipse.xtend.lib;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtend.lib.macro;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.common.types;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.util;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase;version='[2.29.0,2.29.1)',\
|
||||
org.eclipse.xtext.xbase.lib;version='[2.29.0,2.29.1)',\
|
||||
org.objectweb.asm;version='[9.4.0,9.4.1)'
|
||||
org.openhab.core.voice;version='[4.0.0,4.0.1)'
|
||||
|
@ -5,7 +5,7 @@ Fragment-Host: org.openhab.core.thing.xml
|
||||
|
||||
-runrequires: \
|
||||
bnd.identity;id='org.openhab.core.thing.xml.tests',\
|
||||
bnd.identity;id='org.openhab.core.binding.xml'
|
||||
bnd.identity;id='org.openhab.core.addon.xml'
|
||||
|
||||
#
|
||||
# done
|
||||
@ -49,13 +49,13 @@ Fragment-Host: org.openhab.core.thing.xml
|
||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
||||
biz.aQute.tester.junit-platform;version='[6.4.0,6.4.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)',\
|
||||
org.openhab.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.binding.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.addon.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.core;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.config.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.io.console;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.test;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing.xml;version='[4.0.0,4.0.1)',\
|
||||
org.openhab.core.thing.xml.tests;version='[4.0.0,4.0.1)',\
|
||||
com.google.gson;version='[2.9.1,2.9.2)'
|
||||
org.openhab.core.thing.xml.tests;version='[4.0.0,4.0.1)'
|
||||
|
@ -24,7 +24,7 @@
|
||||
<module>org.openhab.core.automation.module.timer.tests</module>
|
||||
<module>org.openhab.core.automation.module.script.tests</module>
|
||||
<module>org.openhab.core.automation.integration.tests</module>
|
||||
<module>org.openhab.core.binding.xml.tests</module>
|
||||
<module>org.openhab.core.addon.xml.tests</module>
|
||||
<module>org.openhab.core.config.core.tests</module>
|
||||
<module>org.openhab.core.config.discovery.mdns.tests</module>
|
||||
<module>org.openhab.core.config.discovery.tests</module>
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="${bindingId}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>${bindingIdCamelCase} Binding</name>
|
||||
<description>This is the binding for ${bindingIdCamelCase}.</description>
|
||||
|
||||
</addon:addon>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="${bindingId}" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>${bindingIdCamelCase} Binding</name>
|
||||
<description>This is the binding for ${bindingIdCamelCase}.</description>
|
||||
|
||||
</binding:binding>
|
@ -51,7 +51,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.core.bundles</groupId>
|
||||
<artifactId>org.openhab.core.binding.xml</artifactId>
|
||||
<artifactId>org.openhab.core.addon.xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -19,7 +19,7 @@ import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.binding.xml.internal.BindingInfoXmlResult;
|
||||
import org.openhab.core.addon.xml.internal.AddonInfoXmlResult;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.thing.xml.internal.ChannelGroupTypeXmlResult;
|
||||
import org.openhab.core.thing.xml.internal.ChannelTypeXmlResult;
|
||||
@ -35,8 +35,8 @@ import com.google.gson.JsonObject;
|
||||
@NonNullByDefault
|
||||
public class BundleInfo {
|
||||
|
||||
private String bindingId = "";
|
||||
private @Nullable BindingInfoXmlResult bindingInfoXml;
|
||||
private String addonId = "";
|
||||
private @Nullable AddonInfoXmlResult addonInfoXml;
|
||||
private List<ConfigDescription> configDescriptions = new ArrayList<>(5);
|
||||
private List<ChannelGroupTypeXmlResult> channelGroupTypesXml = new ArrayList<>(5);
|
||||
private List<ChannelTypeXmlResult> channelTypesXml = new ArrayList<>(5);
|
||||
@ -44,20 +44,20 @@ public class BundleInfo {
|
||||
private List<JsonObject> moduleTypesJson = new ArrayList<>(5);
|
||||
private List<JsonObject> ruleTemplateJson = new ArrayList<>(5);
|
||||
|
||||
public String getBindingId() {
|
||||
return bindingId;
|
||||
public String getAddonId() {
|
||||
return addonId;
|
||||
}
|
||||
|
||||
public void setBindingId(String bindingId) {
|
||||
this.bindingId = bindingId;
|
||||
public void setAddonId(String addonId) {
|
||||
this.addonId = addonId;
|
||||
}
|
||||
|
||||
public @Nullable BindingInfoXmlResult getBindingInfoXml() {
|
||||
return bindingInfoXml;
|
||||
public @Nullable AddonInfoXmlResult getAddonInfoXml() {
|
||||
return addonInfoXml;
|
||||
}
|
||||
|
||||
public void setBindingInfoXml(BindingInfoXmlResult bindingInfo) {
|
||||
this.bindingInfoXml = bindingInfo;
|
||||
public void setAddonInfoXml(AddonInfoXmlResult addonInfo) {
|
||||
this.addonInfoXml = addonInfo;
|
||||
}
|
||||
|
||||
public List<ConfigDescription> getConfigDescriptions() {
|
||||
|
@ -25,8 +25,8 @@ import java.util.stream.StreamSupport;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.binding.xml.internal.BindingInfoReader;
|
||||
import org.openhab.core.binding.xml.internal.BindingInfoXmlResult;
|
||||
import org.openhab.core.addon.xml.internal.AddonInfoReader;
|
||||
import org.openhab.core.addon.xml.internal.AddonInfoXmlResult;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.xml.internal.ConfigDescriptionReader;
|
||||
import org.openhab.core.thing.xml.internal.ChannelGroupTypeXmlResult;
|
||||
@ -58,7 +58,7 @@ public class BundleInfoReader {
|
||||
|
||||
public BundleInfo readBundleInfo(Path ohinfPath) throws IOException {
|
||||
BundleInfo bundleInfo = new BundleInfo();
|
||||
readBindingInfo(ohinfPath, bundleInfo);
|
||||
readAddonInfo(ohinfPath, bundleInfo);
|
||||
readConfigInfo(ohinfPath, bundleInfo);
|
||||
readThingInfo(ohinfPath, bundleInfo);
|
||||
readModuleTypeInfo(ohinfPath, bundleInfo);
|
||||
@ -73,16 +73,16 @@ public class BundleInfoReader {
|
||||
: Stream.of();
|
||||
}
|
||||
|
||||
private void readBindingInfo(Path ohinfPath, BundleInfo bundleInfo) throws IOException {
|
||||
BindingInfoReader reader = new BindingInfoReader();
|
||||
try (Stream<Path> xmlPathStream = xmlPathStream(ohinfPath, "binding")) {
|
||||
private void readAddonInfo(Path ohinfPath, BundleInfo bundleInfo) throws IOException {
|
||||
AddonInfoReader reader = new AddonInfoReader();
|
||||
try (Stream<Path> xmlPathStream = xmlPathStream(ohinfPath, "addon")) {
|
||||
xmlPathStream.forEach(path -> {
|
||||
log.info("Reading: " + path);
|
||||
try {
|
||||
BindingInfoXmlResult bindingInfoXml = reader.readFromXML(path.toUri().toURL());
|
||||
AddonInfoXmlResult bindingInfoXml = reader.readFromXML(path.toUri().toURL());
|
||||
if (bindingInfoXml != null) {
|
||||
bundleInfo.setBindingId(bindingInfoXml.getBindingInfo().getUID());
|
||||
bundleInfo.setBindingInfoXml(bindingInfoXml);
|
||||
bundleInfo.setAddonId(bindingInfoXml.addonInfo().getId());
|
||||
bundleInfo.setAddonInfoXml(bindingInfoXml);
|
||||
}
|
||||
} catch (ConversionException | MalformedURLException e) {
|
||||
log.warn("Exception while reading binding info from: " + path, e);
|
||||
@ -119,20 +119,20 @@ public class BundleInfoReader {
|
||||
if (type instanceof ThingTypeXmlResult) {
|
||||
ThingTypeXmlResult result = (ThingTypeXmlResult) type;
|
||||
bundleInfo.getThingTypesXml().add(result);
|
||||
if (bundleInfo.getBindingId().isBlank()) {
|
||||
bundleInfo.setBindingId(result.getUID().getBindingId());
|
||||
if (bundleInfo.getAddonId().isBlank()) {
|
||||
bundleInfo.setAddonId(result.getUID().getBindingId());
|
||||
}
|
||||
} else if (type instanceof ChannelGroupTypeXmlResult) {
|
||||
ChannelGroupTypeXmlResult result = (ChannelGroupTypeXmlResult) type;
|
||||
bundleInfo.getChannelGroupTypesXml().add(result);
|
||||
if (bundleInfo.getBindingId().isBlank()) {
|
||||
bundleInfo.setBindingId(result.getUID().getBindingId());
|
||||
if (bundleInfo.getAddonId().isBlank()) {
|
||||
bundleInfo.setAddonId(result.getUID().getBindingId());
|
||||
}
|
||||
} else if (type instanceof ChannelTypeXmlResult) {
|
||||
ChannelTypeXmlResult result = (ChannelTypeXmlResult) type;
|
||||
bundleInfo.getChannelTypesXml().add(result);
|
||||
if (bundleInfo.getBindingId().isBlank()) {
|
||||
bundleInfo.setBindingId(result.toChannelType().getUID().getBindingId());
|
||||
if (bundleInfo.getAddonId().isBlank()) {
|
||||
bundleInfo.setAddonId(result.toChannelType().getUID().getBindingId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public class GenerateDefaultTranslationsMojo extends AbstractI18nMojo {
|
||||
}
|
||||
|
||||
private String propertiesFileName(BundleInfo bundleInfo) {
|
||||
String name = bundleInfo.getBindingId();
|
||||
String name = bundleInfo.getAddonId();
|
||||
if (name.isEmpty()) {
|
||||
Optional<ConfigDescription> optional = bundleInfo.getConfigDescriptions().stream().findFirst();
|
||||
if (optional.isPresent()) {
|
||||
|
@ -25,8 +25,8 @@ import java.util.stream.Stream;
|
||||
import java.util.stream.Stream.Builder;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.binding.BindingInfo;
|
||||
import org.openhab.core.binding.xml.internal.BindingInfoXmlResult;
|
||||
import org.openhab.core.addon.AddonInfo;
|
||||
import org.openhab.core.addon.xml.internal.AddonInfoXmlResult;
|
||||
import org.openhab.core.config.core.ConfigDescription;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||
import org.openhab.core.config.core.ConfigDescriptionParameterGroup;
|
||||
@ -54,14 +54,14 @@ public class XmlToTranslationsConverter {
|
||||
private static final Pattern OPTION_ESCAPE_PATTERN = Pattern.compile("([ :=])");
|
||||
|
||||
public Translations convert(BundleInfo bundleInfo) {
|
||||
String bindingId = bundleInfo.getBindingId();
|
||||
return bindingId.isBlank() ? configTranslations(bundleInfo) : bindingTranslations(bundleInfo);
|
||||
String addonId = bundleInfo.getAddonId();
|
||||
return addonId.isBlank() ? configTranslations(bundleInfo) : addonTranslations(bundleInfo);
|
||||
}
|
||||
|
||||
private Translations bindingTranslations(BundleInfo bundleInfo) {
|
||||
private Translations addonTranslations(BundleInfo bundleInfo) {
|
||||
return Translations.translations( //
|
||||
bindingSection(bundleInfo), //
|
||||
bindingConfigSection(bundleInfo), //
|
||||
addonSection(bundleInfo), //
|
||||
addonConfigSection(bundleInfo), //
|
||||
thingTypesSection(bundleInfo), //
|
||||
thingTypesConfigSection(bundleInfo), //
|
||||
channelGroupTypesSection(bundleInfo), //
|
||||
@ -85,39 +85,39 @@ public class XmlToTranslationsConverter {
|
||||
return Translations.translations(section(groupsBuilder.build()));
|
||||
}
|
||||
|
||||
private TranslationsSection bindingSection(BundleInfo bundleInfo) {
|
||||
String header = "binding";
|
||||
BindingInfoXmlResult bindingInfoXml = bundleInfo.getBindingInfoXml();
|
||||
if (bindingInfoXml == null) {
|
||||
private TranslationsSection addonSection(BundleInfo bundleInfo) {
|
||||
String header = "add-on";
|
||||
AddonInfoXmlResult addonInfoXml = bundleInfo.getAddonInfoXml();
|
||||
if (addonInfoXml == null) {
|
||||
return section(header);
|
||||
}
|
||||
|
||||
BindingInfo bindingInfo = bindingInfoXml.getBindingInfo();
|
||||
String bindingId = bundleInfo.getBindingId();
|
||||
AddonInfo addonInfo = addonInfoXml.addonInfo();
|
||||
String addonId = bundleInfo.getAddonId();
|
||||
|
||||
String keyPrefix = String.format("binding.%s", bindingId);
|
||||
String keyPrefix = String.format("addon.%s", addonId);
|
||||
|
||||
return section(header, group( //
|
||||
entry(String.format("%s.name", keyPrefix), bindingInfo.getName()),
|
||||
entry(String.format("%s.description", keyPrefix), bindingInfo.getDescription()) //
|
||||
entry(String.format("%s.name", keyPrefix), addonInfo.getName()),
|
||||
entry(String.format("%s.description", keyPrefix), addonInfo.getDescription()) //
|
||||
));
|
||||
}
|
||||
|
||||
private TranslationsSection bindingConfigSection(BundleInfo bundleInfo) {
|
||||
String header = "binding config";
|
||||
BindingInfoXmlResult bindingInfoXml = bundleInfo.getBindingInfoXml();
|
||||
if (bindingInfoXml == null) {
|
||||
private TranslationsSection addonConfigSection(BundleInfo bundleInfo) {
|
||||
String header = "add-on config";
|
||||
AddonInfoXmlResult addonInfoXml = bundleInfo.getAddonInfoXml();
|
||||
if (addonInfoXml == null) {
|
||||
return section(header);
|
||||
}
|
||||
ConfigDescription bindingConfig = bindingInfoXml.getConfigDescription();
|
||||
if (bindingConfig == null) {
|
||||
ConfigDescription addonConfig = addonInfoXml.configDescription();
|
||||
if (addonConfig == null) {
|
||||
return section(header);
|
||||
}
|
||||
|
||||
String keyPrefix = String.format("binding.config.%s", bundleInfo.getBindingId());
|
||||
String keyPrefix = String.format("addon.config.%s", bundleInfo.getAddonId());
|
||||
return section(header,
|
||||
Stream.concat(configDescriptionGroupParameters(keyPrefix, bindingConfig.getParameterGroups()),
|
||||
configDescriptionParameters(keyPrefix, bindingConfig.getParameters())));
|
||||
Stream.concat(configDescriptionGroupParameters(keyPrefix, addonConfig.getParameterGroups()),
|
||||
configDescriptionParameters(keyPrefix, addonConfig.getParameters())));
|
||||
}
|
||||
|
||||
private TranslationsSection thingTypesSection(BundleInfo bundleInfo) {
|
||||
@ -127,8 +127,8 @@ public class XmlToTranslationsConverter {
|
||||
return section(header);
|
||||
}
|
||||
|
||||
String bindingId = bundleInfo.getBindingId();
|
||||
String keyPrefix = String.format("thing-type.%s", bindingId);
|
||||
String addonId = bundleInfo.getAddonId();
|
||||
String keyPrefix = String.format("thing-type.%s", addonId);
|
||||
|
||||
return section(header, thingTypesXml.stream().map(thingTypeXml -> {
|
||||
ThingType thingType = thingTypeXml.toThingType();
|
||||
@ -216,7 +216,7 @@ public class XmlToTranslationsConverter {
|
||||
return section(header);
|
||||
}
|
||||
|
||||
String keyPrefix = String.format("channel-group-type.%s", bundleInfo.getBindingId());
|
||||
String keyPrefix = String.format("channel-group-type.%s", bundleInfo.getAddonId());
|
||||
|
||||
return section(header, channelGroupTypesXml.stream().map(ChannelGroupTypeXmlResult::toChannelGroupType)
|
||||
.map(channelGroupType -> {
|
||||
@ -258,7 +258,7 @@ public class XmlToTranslationsConverter {
|
||||
return section(header);
|
||||
}
|
||||
|
||||
String keyPrefix = String.format("channel-type.%s", bundleInfo.getBindingId());
|
||||
String keyPrefix = String.format("channel-type.%s", bundleInfo.getAddonId());
|
||||
|
||||
return section(header, channelTypesXml.stream().map(channelTypeXml -> {
|
||||
ChannelType channelType = channelTypeXml.toChannelType();
|
||||
|
@ -21,7 +21,7 @@ import java.nio.file.Path;
|
||||
import org.apache.maven.plugin.logging.SystemStreamLog;
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.core.binding.xml.internal.BindingInfoXmlResult;
|
||||
import org.openhab.core.addon.xml.internal.AddonInfoXmlResult;
|
||||
|
||||
/**
|
||||
* Tests {@link BundleInfoReader}.
|
||||
@ -36,15 +36,15 @@ public class BundleInfoReaderTest {
|
||||
BundleInfoReader reader = new BundleInfoReader(new SystemStreamLog());
|
||||
BundleInfo bundleInfo = reader.readBundleInfo(Path.of("src/test/resources/acmeweather.bundle/OH-INF"));
|
||||
|
||||
BindingInfoXmlResult bindingInfoXml = bundleInfo.getBindingInfoXml();
|
||||
assertThat(bindingInfoXml, is(notNullValue()));
|
||||
if (bindingInfoXml != null) {
|
||||
assertThat(bindingInfoXml.getBindingInfo().getName(), is("ACME Weather Binding"));
|
||||
assertThat(bindingInfoXml.getBindingInfo().getDescription(),
|
||||
AddonInfoXmlResult addonInfoXml = bundleInfo.getAddonInfoXml();
|
||||
assertThat(addonInfoXml, is(notNullValue()));
|
||||
if (addonInfoXml != null) {
|
||||
assertThat(addonInfoXml.addonInfo().getName(), is("ACME Weather Binding"));
|
||||
assertThat(addonInfoXml.addonInfo().getDescription(),
|
||||
is("ACME Weather - Current weather and forecasts in your city."));
|
||||
}
|
||||
|
||||
assertThat(bundleInfo.getBindingId(), is("acmeweather"));
|
||||
assertThat(bundleInfo.getAddonId(), is("acmeweather"));
|
||||
assertThat(bundleInfo.getChannelGroupTypesXml().size(), is(1));
|
||||
assertThat(bundleInfo.getChannelTypesXml().size(), is(2));
|
||||
assertThat(bundleInfo.getConfigDescriptions().size(), is(1));
|
||||
@ -58,8 +58,8 @@ public class BundleInfoReaderTest {
|
||||
BundleInfoReader reader = new BundleInfoReader(new SystemStreamLog());
|
||||
BundleInfo bundleInfo = reader.readBundleInfo(Path.of("src/test/resources/acmetts.bundle/OH-INF"));
|
||||
|
||||
assertThat(bundleInfo.getBindingInfoXml(), is(nullValue()));
|
||||
assertThat(bundleInfo.getBindingId(), is(""));
|
||||
assertThat(bundleInfo.getAddonInfoXml(), is(nullValue()));
|
||||
assertThat(bundleInfo.getAddonId(), is(""));
|
||||
assertThat(bundleInfo.getChannelGroupTypesXml().size(), is(0));
|
||||
assertThat(bundleInfo.getChannelTypesXml().size(), is(0));
|
||||
assertThat(bundleInfo.getConfigDescriptions().size(), is(1));
|
||||
@ -73,8 +73,8 @@ public class BundleInfoReaderTest {
|
||||
BundleInfoReader reader = new BundleInfoReader(new SystemStreamLog());
|
||||
BundleInfo bundleInfo = reader.readBundleInfo(Path.of("src/test/resources/infoless.bundle/OH-INF"));
|
||||
|
||||
assertThat(bundleInfo.getBindingInfoXml(), is(nullValue()));
|
||||
assertThat(bundleInfo.getBindingId(), is(""));
|
||||
assertThat(bundleInfo.getAddonInfoXml(), is(nullValue()));
|
||||
assertThat(bundleInfo.getAddonId(), is(""));
|
||||
assertThat(bundleInfo.getChannelGroupTypesXml().size(), is(0));
|
||||
assertThat(bundleInfo.getChannelTypesXml().size(), is(0));
|
||||
assertThat(bundleInfo.getConfigDescriptions().size(), is(0));
|
||||
|
@ -123,7 +123,7 @@ public class GenerateDefaultTranslationsMojoTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMissingBindingTranslationsWithoutI18nPath() throws IOException, MojoFailureException {
|
||||
public void addMissingAddonTranslationsWithoutI18nPath() throws IOException, MojoFailureException {
|
||||
copyPath(WEATHER_RESOURCES_PATH, tempPath);
|
||||
deleteTempI18nPath();
|
||||
|
||||
@ -134,7 +134,7 @@ public class GenerateDefaultTranslationsMojoTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMissingBindingTranslationsNoChanges() throws IOException, MojoFailureException {
|
||||
public void addMissingAddonTranslationsNoChanges() throws IOException, MojoFailureException {
|
||||
copyPath(WEATHER_RESOURCES_PATH, tempPath);
|
||||
|
||||
mojo.setGenerationMode(ADD_MISSING_TRANSLATIONS);
|
||||
|
@ -42,10 +42,10 @@ public class PropertiesToTranslationsConverterTest {
|
||||
assertThat(translations.keysStream().count(), is(44L));
|
||||
|
||||
String lines = translations.linesStream().collect(Collectors.joining(System.lineSeparator()));
|
||||
assertThat(lines, containsString("# binding"));
|
||||
assertThat(lines, containsString("binding.acmeweather.name = ACME Weather Binding"));
|
||||
assertThat(lines, containsString("# add-on"));
|
||||
assertThat(lines, containsString("addon.acmeweather.name = ACME Weather Binding"));
|
||||
assertThat(lines, containsString(
|
||||
"binding.acmeweather.description = ACME Weather - Current weather and forecasts in your city."));
|
||||
"addon.acmeweather.description = ACME Weather - Current weather and forecasts in your city."));
|
||||
assertThat(lines, containsString(
|
||||
"channel-group-type.acmeweather.forecast.channel.minTemperature.description = Minimum forecasted temperature in degrees Celsius (metric) or Fahrenheit (imperial)."));
|
||||
assertThat(lines, containsString(
|
||||
|
@ -45,10 +45,10 @@ public class XmlToTranslationsConverterTest {
|
||||
assertThat(translations.keysStream().count(), is(34L));
|
||||
|
||||
String lines = translations.linesStream().collect(Collectors.joining(System.lineSeparator()));
|
||||
assertThat(lines, containsString("# binding"));
|
||||
assertThat(lines, containsString("binding.acmeweather.name = ACME Weather Binding"));
|
||||
assertThat(lines, containsString("# add-on"));
|
||||
assertThat(lines, containsString("addon.acmeweather.name = ACME Weather Binding"));
|
||||
assertThat(lines, containsString(
|
||||
"binding.acmeweather.description = ACME Weather - Current weather and forecasts in your city."));
|
||||
"addon.acmeweather.description = ACME Weather - Current weather and forecasts in your city."));
|
||||
assertThat(lines, containsString(
|
||||
"channel-group-type.acmeweather.forecast.channel.minTemperature.description = Minimum forecasted temperature in degrees Celsius (metric) or Fahrenheit (imperial)."));
|
||||
assertThat(lines, containsString(
|
||||
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="acmeweather" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>ACME Weather Binding</name>
|
||||
<description>ACME Weather - Current weather and forecasts in your city.</description>
|
||||
|
||||
</addon:addon>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="acmeweather" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>ACME Weather Binding</name>
|
||||
<description>ACME Weather - Current weather and forecasts in your city.</description>
|
||||
|
||||
</binding:binding>
|
@ -1,7 +1,7 @@
|
||||
# binding
|
||||
# add-on
|
||||
|
||||
binding.acmeweather.name = ACME Weather Binding
|
||||
binding.acmeweather.description = ACME Weather - Current weather and forecasts in your city.
|
||||
addon.acmeweather.name = ACME Weather Binding
|
||||
addon.acmeweather.description = ACME Weather - Current weather and forecasts in your city.
|
||||
|
||||
# thing types
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# binding
|
||||
# add-on
|
||||
|
||||
binding.acmeweather.name = ACME Weather Binding
|
||||
binding.acmeweather.description = ACME Weather - Current weather and forecasts in your city.
|
||||
addon.acmeweather.name = ACME Weather Binding
|
||||
addon.acmeweather.description = ACME Weather - Current weather and forecasts in your city.
|
||||
|
||||
# thing types
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# binding
|
||||
# add-on
|
||||
|
||||
binding.acmeweather.name = ACME Wetter Binding
|
||||
binding.acmeweather.description = ACME Wetter - Aktuelles Wetter und Prognosen in Ihrer Stadt.
|
||||
addon.acmeweather.name = ACME Wetter Binding
|
||||
addon.acmeweather.description = ACME Wetter - Aktuelles Wetter und Prognosen in Ihrer Stadt.
|
||||
|
||||
# thing types
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user