Skip to content

Commit

Permalink
AddonInfo extensions (#3865)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Fiddian-Green <[email protected]>
  • Loading branch information
andrewfg authored Dec 5, 2023
1 parent aa305d9 commit cc9b705
Show file tree
Hide file tree
Showing 20 changed files with 1,172 additions and 48 deletions.
82 changes: 55 additions & 27 deletions bundles/org.openhab.core.addon/schema/addon-1.0.0.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,36 @@
<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="addon:addonType"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="connection" type="addon:connectionType" minOccurs="0"/>
<xs:element name="countries" type="addon: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 &lt;type&gt;.&lt;name&gt;</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:element name="addon" type="addon:addonInfo"/>

<xs:complexType name="addonInfo">
<xs:sequence>
<xs:element name="type" type="addon:addonType"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="description" type="xs:string"/>
<xs:element name="connection" type="addon:connectionType" minOccurs="0"/>
<xs:element name="countries" type="addon: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 is used to construct the UID of this add-on to &lt;type&gt;-&lt;name&gt;</xs:documentation>
<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 &lt;type&gt;.&lt;name&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</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:element name="discovery-methods" type="addon:discoveryMethodsType" minOccurs="0"/>
</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 &lt;type&gt;-&lt;name&gt;</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>

<xs:simpleType name="addonType">
<xs:restriction base="xs:string">
Expand Down Expand Up @@ -80,4 +81,31 @@
</xs:restriction>
</xs:simpleType>

<xs:complexType name="discoveryMethodsType">
<xs:sequence>
<xs:element type="addon:discoveryMethodType" name="discovery-method" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="discoveryMethodType">
<xs:sequence>
<xs:element type="xs:string" name="service-type"/>
<xs:element type="xs:string" name="mdns-service-type" minOccurs="0"/>
<xs:element type="addon:matchPropertiesType" name="match-properties" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="matchPropertiesType">
<xs:sequence>
<xs:element type="addon:matchPropertyType" name="match-property" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="matchPropertyType">
<xs:sequence>
<xs:element type="xs:string" name="name"/>
<xs:element type="xs:string" name="regex"/>
</xs:sequence>
</xs:complexType>

</xs:schema>
23 changes: 23 additions & 0 deletions bundles/org.openhab.core.addon/schema/addon-info-list-1.0.0.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
xmlns:addon-info-list="https://openhab.org/schemas/addon-info-list/v1.0.0"
targetNamespace="https://openhab.org/schemas/addon-info-list/v1.0.0">

<xs:import namespace="https://openhab.org/schemas/addon/v1.0.0" schemaLocation="addon-1.0.0.xsd"/>

<xs:element name="addon-info-list">
<xs:complexType>
<xs:sequence>
<xs:element name="addons" type="addon-info-list:addons"/>
</xs:sequence>
</xs:complexType>
</xs:element>

<xs:complexType name="addons">
<xs:sequence>
<xs:element name="addon" type="addon:addonInfo" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

</xs:schema>
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* 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 org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
* DTO for serialization of a suggested addon discovery method.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class AddonDiscoveryMethod {
private @NonNullByDefault({}) String serviceType;
private @Nullable String mdnsServiceType;
private @Nullable List<AddonMatchProperty> matchProperties;

public String getServiceType() {
return serviceType.toLowerCase();
}

public String getMdnsServiceType() {
String mdnsServiceType = this.mdnsServiceType;
return mdnsServiceType != null ? mdnsServiceType : "";
}

public List<AddonMatchProperty> getMatchProperties() {
List<AddonMatchProperty> matchProperties = this.matchProperties;
return matchProperties != null ? matchProperties : List.of();
}

public AddonDiscoveryMethod setServiceType(String serviceType) {
this.serviceType = serviceType.toLowerCase();
return this;
}

public AddonDiscoveryMethod setMdnsServiceType(@Nullable String mdnsServiceType) {
this.mdnsServiceType = mdnsServiceType;
return this;
}

public AddonDiscoveryMethod setMatchProperties(@Nullable List<AddonMatchProperty> matchProperties) {
this.matchProperties = matchProperties;
return this;
}

@Override
public int hashCode() {
return Objects.hash(serviceType, mdnsServiceType, matchProperties);
}

@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
AddonDiscoveryMethod other = (AddonDiscoveryMethod) obj;
return Objects.equals(serviceType, other.serviceType) && Objects.equals(mdnsServiceType, other.mdnsServiceType)
&& Objects.equals(matchProperties, other.matchProperties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,20 @@ public class AddonInfo implements Identifiable<String> {

private final String id;
private final String type;
private final String uid;
private final String name;
private final String description;
private final @Nullable String connection;
private final List<String> countries;
private final @Nullable String configDescriptionURI;
private final String serviceId;
private @Nullable String sourceBundle;
private @Nullable List<AddonDiscoveryMethod> discoveryMethods;

private AddonInfo(String id, String type, String name, String description, @Nullable String connection,
List<String> countries, @Nullable String configDescriptionURI, @Nullable String serviceId,
@Nullable String sourceBundle) throws IllegalArgumentException {
private AddonInfo(String id, String type, @Nullable String uid, String name, String description,
@Nullable String connection, List<String> countries, @Nullable String configDescriptionURI,
@Nullable String serviceId, @Nullable String sourceBundle,
@Nullable List<AddonDiscoveryMethod> discoveryMethods) throws IllegalArgumentException {
// mandatory fields
if (id.isBlank()) {
throw new IllegalArgumentException("The ID must neither be null nor empty!");
Expand All @@ -64,6 +67,7 @@ private AddonInfo(String id, String type, String name, String description, @Null
}
this.id = id;
this.type = type;
this.uid = uid != null ? uid : type + Addon.ADDON_SEPARATOR + id;
this.name = name;
this.description = description;

Expand All @@ -73,6 +77,7 @@ private AddonInfo(String id, String type, String name, String description, @Null
this.configDescriptionURI = configDescriptionURI;
this.serviceId = Objects.requireNonNullElse(serviceId, type + "." + id);
this.sourceBundle = sourceBundle;
this.discoveryMethods = discoveryMethods;
}

/**
Expand All @@ -82,7 +87,7 @@ private AddonInfo(String id, String type, String name, String description, @Null
*/
@Override
public String getUID() {
return type + Addon.ADDON_SEPARATOR + id;
return uid;
}

/**
Expand Down Expand Up @@ -142,6 +147,11 @@ public List<String> getCountries() {
return countries;
}

public List<AddonDiscoveryMethod> getDiscoveryMethods() {
List<AddonDiscoveryMethod> discoveryMethods = this.discoveryMethods;
return discoveryMethods != null ? discoveryMethods : List.of();
}

public static Builder builder(String id, String type) {
return new Builder(id, type);
}
Expand All @@ -154,13 +164,15 @@ public static class Builder {

private final String id;
private final String type;
private @Nullable String uid;
private String name = "";
private String description = "";
private @Nullable String connection;
private List<String> countries = List.of();
private @Nullable String configDescriptionURI = "";
private @Nullable String serviceId;
private @Nullable String sourceBundle;
private @Nullable List<AddonDiscoveryMethod> discoveryMethods;

private Builder(String id, String type) {
this.id = id;
Expand All @@ -170,13 +182,20 @@ private Builder(String id, String type) {
private Builder(AddonInfo addonInfo) {
this.id = addonInfo.id;
this.type = addonInfo.type;
this.uid = addonInfo.uid;
this.name = addonInfo.name;
this.description = addonInfo.description;
this.connection = addonInfo.connection;
this.countries = addonInfo.countries;
this.configDescriptionURI = addonInfo.configDescriptionURI;
this.serviceId = addonInfo.serviceId;
this.sourceBundle = addonInfo.sourceBundle;
this.discoveryMethods = addonInfo.discoveryMethods;
}

public Builder withUID(@Nullable String uid) {
this.uid = uid;
return this;
}

public Builder withName(String name) {
Expand Down Expand Up @@ -219,15 +238,20 @@ public Builder withSourceBundle(@Nullable String sourceBundle) {
return this;
}

public Builder withDiscoveryMethods(@Nullable List<AddonDiscoveryMethod> discoveryMethods) {
this.discoveryMethods = discoveryMethods;
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, connection, countries, configDescriptionURI, serviceId,
sourceBundle);
return new AddonInfo(id, type, uid, name, description, connection, countries, configDescriptionURI,
serviceId, sourceBundle, discoveryMethods);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* 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 org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

/**
* DTO containing a list of {@code AddonInfo}
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class AddonInfoList {
protected @Nullable List<AddonInfo> addons;

public List<AddonInfo> getAddons() {
List<AddonInfo> addons = this.addons;
return addons != null ? addons : List.of();
}

public AddonInfoList setAddons(@Nullable List<AddonInfo> addons) {
this.addons = addons;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@
public interface AddonInfoProvider {

/**
* Returns the binding information for the specified binding ID and locale (language),
* Returns the binding information for the specified binding UID 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 uid the UID 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)
*/
@Nullable
AddonInfo getAddonInfo(@Nullable String id, @Nullable Locale locale);
AddonInfo getAddonInfo(@Nullable String uid, @Nullable Locale locale);

/**
* Returns all binding information in the specified locale (language) this provider contains.
Expand Down
Loading

0 comments on commit cc9b705

Please sign in to comment.