diff --git a/bom/openhab-core/pom.xml b/bom/openhab-core/pom.xml
index 4b2994199..1bea7c150 100644
--- a/bom/openhab-core/pom.xml
+++ b/bom/openhab-core/pom.xml
@@ -514,6 +514,12 @@
${project.version}
compile
+
+ org.openhab.core.bundles
+ org.openhab.core.addon.eclipse
+ ${project.version}
+ compile
+
org.openhab.core.bundles
org.openhab.core.addon.marketplace
diff --git a/bundles/org.openhab.core.addon.sample/.classpath b/bundles/org.openhab.core.addon.eclipse/.classpath
similarity index 100%
rename from bundles/org.openhab.core.addon.sample/.classpath
rename to bundles/org.openhab.core.addon.eclipse/.classpath
diff --git a/bundles/org.openhab.core.addon.eclipse/.project b/bundles/org.openhab.core.addon.eclipse/.project
new file mode 100644
index 000000000..e4a6b7cc6
--- /dev/null
+++ b/bundles/org.openhab.core.addon.eclipse/.project
@@ -0,0 +1,23 @@
+
+
+ org.openhab.core.addon.sample
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/bundles/org.openhab.core.addon.sample/NOTICE b/bundles/org.openhab.core.addon.eclipse/NOTICE
similarity index 100%
rename from bundles/org.openhab.core.addon.sample/NOTICE
rename to bundles/org.openhab.core.addon.eclipse/NOTICE
diff --git a/bundles/org.openhab.core.addon.sample/pom.xml b/bundles/org.openhab.core.addon.eclipse/pom.xml
similarity index 87%
rename from bundles/org.openhab.core.addon.sample/pom.xml
rename to bundles/org.openhab.core.addon.eclipse/pom.xml
index 25c3806c3..413299f72 100644
--- a/bundles/org.openhab.core.addon.sample/pom.xml
+++ b/bundles/org.openhab.core.addon.eclipse/pom.xml
@@ -10,9 +10,9 @@
4.0.0-SNAPSHOT
- org.openhab.core.addon.sample
+ org.openhab.core.addon.eclipse
- openHAB Core :: Bundles :: Sample Add-on Service
+ openHAB Core :: Bundles :: Eclipse Add-on Service
diff --git a/bundles/org.openhab.core.addon.eclipse/src/main/java/org/openhab/core/addon/eclipse/internal/EclipseAddonService.java b/bundles/org.openhab.core.addon.eclipse/src/main/java/org/openhab/core/addon/eclipse/internal/EclipseAddonService.java
new file mode 100644
index 000000000..1a28c50d7
--- /dev/null
+++ b/bundles/org.openhab.core.addon.eclipse/src/main/java/org/openhab/core/addon/eclipse/internal/EclipseAddonService.java
@@ -0,0 +1,193 @@
+/**
+ * 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.eclipse.internal;
+
+import static java.util.Map.entry;
+import static org.openhab.core.addon.AddonType.*;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+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.config.core.ConfigurableService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+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;
+
+/**
+ * This is an implementation of an {@link AddonService} that can be used when debugging in Eclipse.
+ *
+ * @author Wouter Born - Initial contribution
+ */
+@Component(name = "org.openhab.addons")
+@NonNullByDefault
+@ConfigurableService(category = "system", label = "Add-on Management", description_uri = EclipseAddonService.CONFIG_URI)
+public class EclipseAddonService implements AddonService {
+
+ public static final String CONFIG_URI = "system:addons";
+
+ private static final String SERVICE_ID = "eclipse";
+ private static final String ADDON_ID_PREFIX = SERVICE_ID + ":";
+
+ private static final String ADDONS_CONTENT_TYPE = "application/vnd.openhab.bundle";
+ private static final String ADDONS_AUTHOR = "openHAB";
+ private static final String BUNDLE_SYMBOLIC_NAME_PREFIX = "org.openhab.";
+
+ private static final Map ADDON_BUNDLE_TYPE_MAP = Map.ofEntries(
+ entry(AUTOMATION.getId(), "automation"), //
+ entry(BINDING.getId(), "binding"), //
+ entry(MISC.getId(), "io"), //
+ entry(PERSISTENCE.getId(), "persistence"), //
+ entry(TRANSFORMATION.getId(), "transform"), //
+ entry(UI.getId(), "ui"), //
+ entry(VOICE.getId(), "voice"));
+
+ private static final Map BUNDLE_ADDON_TYPE_MAP = ADDON_BUNDLE_TYPE_MAP.entrySet().stream()
+ .collect(Collectors.toMap(Entry::getValue, Entry::getKey));
+
+ private static final String DOCUMENTATION_URL_PREFIX = "https://www.openhab.org/addons/";
+
+ private static final Map DOCUMENTATION_URL_FORMATS = Map.ofEntries(
+ entry(AUTOMATION.getId(), DOCUMENTATION_URL_PREFIX + "automation/%s/"), //
+ entry(BINDING.getId(), DOCUMENTATION_URL_PREFIX + "bindings/%s/"), //
+ entry(MISC.getId(), DOCUMENTATION_URL_PREFIX + "integrations/%s/"), //
+ entry(PERSISTENCE.getId(), DOCUMENTATION_URL_PREFIX + "persistence/%s/"), //
+ entry(TRANSFORMATION.getId(), DOCUMENTATION_URL_PREFIX + "transformations/%s/"), //
+ entry(UI.getId(), DOCUMENTATION_URL_PREFIX + "ui/%s/"), //
+ entry(VOICE.getId(), DOCUMENTATION_URL_PREFIX + "voice/%s/"));
+
+ private final BundleContext bundleContext;
+ private final AddonInfoRegistry addonInfoRegistry;
+
+ @Activate
+ public EclipseAddonService(BundleContext bundleContext, @Reference AddonInfoRegistry addonInfoRegistry) {
+ this.bundleContext = bundleContext;
+ this.addonInfoRegistry = addonInfoRegistry;
+ }
+
+ @Deactivate
+ protected void deactivate() {
+ }
+
+ @Override
+ public String getId() {
+ return SERVICE_ID;
+ }
+
+ @Override
+ public String getName() {
+ return "Eclipse Add-on Service";
+ }
+
+ @Override
+ public void refreshSource() {
+ }
+
+ @Override
+ public void install(String id) {
+ throw new UnsupportedOperationException(getName() + " does not support installing add-ons");
+ }
+
+ @Override
+ public void uninstall(String id) {
+ throw new UnsupportedOperationException(getName() + " does not support uninstalling add-ons");
+ }
+
+ private boolean isAddon(Bundle bundle) {
+ String symbolicName = bundle.getSymbolicName();
+ String[] segments = symbolicName.split("\\.");
+ return symbolicName.startsWith(BUNDLE_SYMBOLIC_NAME_PREFIX) && bundle.getState() == Bundle.ACTIVE
+ && segments.length >= 4 && ADDON_BUNDLE_TYPE_MAP.containsValue(segments[2]);
+ }
+
+ private Addon getAddon(Bundle bundle, @Nullable Locale locale) {
+ String symbolicName = bundle.getSymbolicName();
+ String[] segments = symbolicName.split("\\.");
+
+ String type = Objects.requireNonNull(BUNDLE_ADDON_TYPE_MAP.get(segments[2]));
+ String name = segments[3];
+
+ String uid = type + Addon.ADDON_SEPARATOR + name;
+
+ Addon.Builder addon = Addon.create(ADDON_ID_PREFIX + uid).withType(type).withId(name)
+ .withContentType(ADDONS_CONTENT_TYPE).withVersion(bundle.getVersion().toString())
+ .withAuthor(ADDONS_AUTHOR, true).withInstalled(true);
+
+ AddonInfo addonInfo = addonInfoRegistry.getAddonInfo(uid, locale);
+
+ if (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(name).withLink(getDefaultDocumentationLink(type, name));
+ }
+
+ addon.withLoggerPackages(List.of(symbolicName));
+
+ return addon.build();
+ }
+
+ @Override
+ public List getAddons(@Nullable Locale locale) {
+ return Arrays.stream(bundleContext.getBundles()) //
+ .filter(this::isAddon) //
+ .map(bundle -> getAddon(bundle, locale)) //
+ .sorted(Comparator.comparing(Addon::getLabel)) //
+ .toList();
+ }
+
+ private @Nullable String getDefaultDocumentationLink(String type, String name) {
+ String format = DOCUMENTATION_URL_FORMATS.get(type);
+ return format == null ? null : String.format(format, name);
+ }
+
+ @Override
+ public @Nullable Addon getAddon(String uid, @Nullable Locale locale) {
+ String id = uid.replaceFirst(ADDON_ID_PREFIX, "");
+ String[] segments = id.split(Addon.ADDON_SEPARATOR);
+ String symbolicName = BUNDLE_SYMBOLIC_NAME_PREFIX + ADDON_BUNDLE_TYPE_MAP.get(segments[0]) + "." + segments[1];
+ return Arrays.stream(bundleContext.getBundles()) //
+ .filter(bundle -> bundle.getSymbolicName().equals(symbolicName)) //
+ .filter(this::isAddon) //
+ .map(bundle -> getAddon(bundle, locale)) //
+ .findFirst().orElse(null);
+ }
+
+ @Override
+ public List getTypes(@Nullable Locale locale) {
+ return AddonType.DEFAULT_TYPES;
+ }
+
+ @Override
+ public @Nullable String getAddonId(URI extensionURI) {
+ return null;
+ }
+}
diff --git a/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/AbstractRemoteAddonService.java b/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/AbstractRemoteAddonService.java
index 233fcdc58..20736dd50 100644
--- a/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/AbstractRemoteAddonService.java
+++ b/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/AbstractRemoteAddonService.java
@@ -20,7 +20,6 @@ import java.util.Dictionary;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -57,15 +56,6 @@ public abstract class AbstractRemoteAddonService implements AddonService {
static final String CONFIG_REMOTE_ENABLED = "remote";
static final String CONFIG_INCLUDE_INCOMPATIBLE = "includeIncompatible";
- protected static final Map TAG_ADDON_TYPE_MAP = Map.of( //
- "automation", new AddonType("automation", "Automation"), //
- "binding", new AddonType("binding", "Bindings"), //
- "misc", new AddonType("misc", "Misc"), //
- "persistence", new AddonType("persistence", "Persistence"), //
- "transformation", new AddonType("transformation", "Transformations"), //
- "ui", new AddonType("ui", "User Interfaces"), //
- "voice", new AddonType("voice", "Voice"));
-
protected final BundleVersion coreVersion;
protected final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create();
@@ -163,7 +153,7 @@ public abstract class AbstractRemoteAddonService implements AddonService {
@Override
public List getTypes(@Nullable Locale locale) {
- return new ArrayList<>(TAG_ADDON_TYPE_MAP.values());
+ return AddonType.DEFAULT_TYPES;
}
@Override
diff --git a/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/internal/community/CommunityMarketplaceAddonService.java b/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/internal/community/CommunityMarketplaceAddonService.java
index 0b89114dc..e5c699cac 100644
--- a/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/internal/community/CommunityMarketplaceAddonService.java
+++ b/bundles/org.openhab.core.addon.marketplace/src/main/java/org/openhab/core/addon/marketplace/internal/community/CommunityMarketplaceAddonService.java
@@ -239,14 +239,15 @@ public class CommunityMarketplaceAddonService extends AbstractRemoteAddonService
private @Nullable AddonType getAddonType(@Nullable Integer category, List tags) {
// check if we can determine the addon type from the category
if (RULETEMPLATES_CATEGORY.equals(category)) {
- return TAG_ADDON_TYPE_MAP.get("automation");
+ return AddonType.AUTOMATION;
} else if (UIWIDGETS_CATEGORY.equals(category)) {
- return TAG_ADDON_TYPE_MAP.get("ui");
+ return AddonType.UI;
} else if (BLOCKLIBRARIES_CATEGORY.equals(category)) {
- return TAG_ADDON_TYPE_MAP.get("automation");
+ return AddonType.AUTOMATION;
} else if (BUNDLES_CATEGORY.equals(category)) {
// try to get it from tags if we have tags
- return tags.stream().map(TAG_ADDON_TYPE_MAP::get).filter(Objects::nonNull).findFirst().orElse(null);
+ return AddonType.DEFAULT_TYPES.stream().filter(type -> tags.contains(type.getId())).findFirst()
+ .orElse(null);
}
// or return null
diff --git a/bundles/org.openhab.core.addon.sample/src/main/java/org/openhab/core/addon/sample/internal/SampleAddonService.java b/bundles/org.openhab.core.addon.sample/src/main/java/org/openhab/core/addon/sample/internal/SampleAddonService.java
deleted file mode 100644
index e9b9ea8f5..000000000
--- a/bundles/org.openhab.core.addon.sample/src/main/java/org/openhab/core/addon/sample/internal/SampleAddonService.java
+++ /dev/null
@@ -1,179 +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.addon.sample.internal;
-
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Random;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.addon.Addon;
-import org.openhab.core.addon.AddonEventFactory;
-import org.openhab.core.addon.AddonService;
-import org.openhab.core.addon.AddonType;
-import org.openhab.core.events.Event;
-import org.openhab.core.events.EventPublisher;
-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;
-
-/**
- * This is an implementation of an {@link AddonService} that can be used as a dummy service for testing the
- * functionality.
- * It is not meant to be used anywhere productively.
- *
- * @author Kai Kreuzer - Initial contribution
- */
-@Component
-@NonNullByDefault
-public class SampleAddonService implements AddonService {
-
- private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
-
- private static final String[] COLOR_VALUES = new String[] { "80", "C8", "FF" };
-
- private final EventPublisher eventPublisher;
-
- private List types = new ArrayList<>(3);
- private Map extensions = new HashMap<>(30);
-
- @Activate
- public SampleAddonService(final @Reference EventPublisher eventPublisher) {
- this.eventPublisher = eventPublisher;
- }
-
- @Activate
- protected void activate() {
- types.add(new AddonType("binding", "Bindings"));
- types.add(new AddonType("ui", "User Interfaces"));
- types.add(new AddonType("persistence", "Persistence Services"));
-
- for (AddonType type : types) {
- for (int i = 0; i < 10; i++) {
- String id = type.getId() + Integer.toString(i);
- boolean installed = Math.random() > 0.5;
- byte[] array = new byte[5];
- new Random().nextBytes(array);
- String name = new String(array, StandardCharsets.UTF_8);
- String typeId = type.getId();
- String label = name + " " + typeId.substring(0, 1).toUpperCase() + typeId.substring(1).toLowerCase();
- String version = "1.0";
- String link = (Math.random() < 0.5) ? null : "http://lmgtfy.com/?q=" + name;
- String description = createDescription();
- String backgroundColor = createRandomColor();
- Addon extension = Addon.create(id).withType(typeId).withLabel(label).withVersion(version)
- .withMaturity("stable").withContentType("example/vnd.openhab.addon").withLink(link)
- .withAuthor("John Doe", false).withInstalled(installed).withDescription(description)
- .withBackgroundColor(backgroundColor).build();
- extensions.put(extension.getUid(), extension);
- }
- }
- }
-
- private static final Random RANDOM = new Random();
-
- private String createRandomColor() {
- StringBuilder ret = new StringBuilder("#");
- for (int i = 0; i < 3; i++) {
- ret.append(COLOR_VALUES[RANDOM.nextInt(COLOR_VALUES.length)]);
- }
- return ret.toString();
- }
-
- private String createDescription() {
- int index = LOREM_IPSUM.indexOf(" ", RANDOM.nextInt(LOREM_IPSUM.length()));
- if (index < 0) {
- index = LOREM_IPSUM.length();
- }
- return LOREM_IPSUM.substring(0, index);
- }
-
- @Deactivate
- protected void deactivate() {
- types.clear();
- extensions.clear();
- }
-
- @Override
- public String getId() {
- return "sample";
- }
-
- @Override
- public String getName() {
- return "Sample Add-on Service";
- }
-
- @Override
- public void refreshSource() {
- }
-
- @Override
- public void install(String id) {
- try {
- Thread.sleep((long) (Math.random() * 10000));
- Addon extension = getAddon(id, null);
- extension.setInstalled(true);
- postInstalledEvent(id);
- } catch (InterruptedException e) {
- }
- }
-
- @Override
- public void uninstall(String id) {
- try {
- Thread.sleep((long) (Math.random() * 5000));
- Addon extension = getAddon(id, null);
- extension.setInstalled(false);
- postUninstalledEvent(id);
- } catch (InterruptedException e) {
- }
- }
-
- @Override
- public List getAddons(@Nullable Locale locale) {
- return new ArrayList<>(extensions.values());
- }
-
- @Override
- public @Nullable Addon getAddon(String id, @Nullable Locale locale) {
- return extensions.get(id);
- }
-
- @Override
- public List getTypes(@Nullable Locale locale) {
- return types;
- }
-
- @Override
- public @Nullable String getAddonId(URI extensionURI) {
- return null;
- }
-
- private void postInstalledEvent(String extensionId) {
- Event event = AddonEventFactory.createAddonInstalledEvent(extensionId);
- eventPublisher.post(event);
- }
-
- private void postUninstalledEvent(String extensionId) {
- Event event = AddonEventFactory.createAddonUninstalledEvent(extensionId);
- eventPublisher.post(event);
- }
-}
diff --git a/bundles/org.openhab.core.addon/.classpath b/bundles/org.openhab.core.addon/.classpath
index 19449de2d..b5320e6c5 100644
--- a/bundles/org.openhab.core.addon/.classpath
+++ b/bundles/org.openhab.core.addon/.classpath
@@ -6,7 +6,12 @@
-
+
+
+
+
+
+
@@ -26,5 +31,10 @@
+
+
+
+
+
diff --git a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonType.java b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonType.java
index 1b1cc139c..84d3cb719 100644
--- a/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonType.java
+++ b/bundles/org.openhab.core.addon/src/main/java/org/openhab/core/addon/AddonType.java
@@ -12,6 +12,8 @@
*/
package org.openhab.core.addon;
+import java.util.List;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@@ -23,6 +25,17 @@ import org.eclipse.jdt.annotation.Nullable;
@NonNullByDefault
public class AddonType {
+ public static final AddonType AUTOMATION = new AddonType("automation", "Automation");
+ public static final AddonType BINDING = new AddonType("binding", "Bindings");
+ public static final AddonType MISC = new AddonType("misc", "Misc");
+ public static final AddonType PERSISTENCE = new AddonType("persistence", "Persistence");
+ public static final AddonType TRANSFORMATION = new AddonType("transformation", "Transformations");
+ public static final AddonType UI = new AddonType("ui", "User Interfaces");
+ public static final AddonType VOICE = new AddonType("voice", "Voice");
+
+ public static final List DEFAULT_TYPES = List.of(AUTOMATION, BINDING, MISC, PERSISTENCE, TRANSFORMATION,
+ UI, VOICE);
+
private final String id;
private final String label;
@@ -64,10 +77,7 @@ public class AddonType {
if (this == obj) {
return true;
}
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
+ if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
return id.equals(((AddonType) obj).id);
diff --git a/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/FeatureInstaller.java b/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/FeatureInstaller.java
index a6fc3b7b2..00eaacfd7 100644
--- a/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/FeatureInstaller.java
+++ b/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/FeatureInstaller.java
@@ -50,6 +50,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.OpenHAB;
import org.openhab.core.addon.AddonEventFactory;
+import org.openhab.core.addon.AddonType;
import org.openhab.core.common.NamedThreadFactory;
import org.openhab.core.config.core.ConfigParser;
import org.openhab.core.config.core.ConfigurableService;
@@ -81,17 +82,6 @@ public class FeatureInstaller implements ConfigurationListener {
protected static final String CONFIG_URI = "system:addons";
- public static final String EXTENSION_TYPE_AUTOMATION = "automation";
- public static final String EXTENSION_TYPE_BINDING = "binding";
- public static final String EXTENSION_TYPE_MISC = "misc";
- public static final String EXTENSION_TYPE_PERSISTENCE = "persistence";
- 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 Set 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 MINIMAL_PACKAGE = "minimal";
@@ -101,6 +91,9 @@ public class FeatureInstaller implements ConfigurationListener {
private static final String ADDONS_PID = "org.openhab.addons";
private static final String PROPERTY_MVN_REPOS = "org.ops4j.pax.url.mvn.repositories";
+ public static final List ADDON_TYPES = AddonType.DEFAULT_TYPES.stream().map(AddonType::getId)
+ .collect(Collectors.toList());
+
private final Logger logger = LoggerFactory.getLogger(FeatureInstaller.class);
private final ConfigurationAdmin configurationAdmin;
@@ -388,7 +381,7 @@ public class FeatureInstaller implements ConfigurationListener {
final Set targetAddons = new HashSet<>(); // the target we want to have installed afterwards
final Set installAddons = new HashSet<>(); // the ones to be installed (the diff)
- for (String type : EXTENSION_TYPES) {
+ for (String type : ADDON_TYPES) {
Object configValue = config.get(type);
if (configValue instanceof String addonString) {
try {
diff --git a/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/KarafAddonService.java b/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/KarafAddonService.java
index 857417058..2fcc9e2de 100644
--- a/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/KarafAddonService.java
+++ b/bundles/org.openhab.core.karaf/src/main/java/org/openhab/core/karaf/internal/KarafAddonService.java
@@ -12,11 +12,15 @@
*/
package org.openhab.core.karaf.internal;
+import static java.util.Map.entry;
+import static org.openhab.core.addon.AddonType.*;
+
import java.net.URI;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
@@ -44,14 +48,17 @@ import org.slf4j.LoggerFactory;
public class KarafAddonService implements AddonService {
private static final String ADDONS_CONTENT_TYPE = "application/vnd.openhab.feature;type=karaf";
private static final String ADDONS_AUTHOR = "openHAB";
- private static final List 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 static final String DOCUMENTATION_URL_PREFIX = "https://www.openhab.org/addons/";
+
+ private static final Map DOCUMENTATION_URL_FORMATS = Map.ofEntries(
+ entry(AUTOMATION.getId(), DOCUMENTATION_URL_PREFIX + "automation/%s/"), //
+ entry(BINDING.getId(), DOCUMENTATION_URL_PREFIX + "bindings/%s/"), //
+ entry(MISC.getId(), DOCUMENTATION_URL_PREFIX + "integrations/%s/"), //
+ entry(PERSISTENCE.getId(), DOCUMENTATION_URL_PREFIX + "persistence/%s/"), //
+ entry(TRANSFORMATION.getId(), DOCUMENTATION_URL_PREFIX + "transformations/%s/"), //
+ entry(UI.getId(), DOCUMENTATION_URL_PREFIX + "ui/%s/"), //
+ entry(VOICE.getId(), DOCUMENTATION_URL_PREFIX + "voice/%s/"));
private final Logger logger = LoggerFactory.getLogger(KarafAddonService.class);
@@ -95,7 +102,7 @@ public class KarafAddonService implements AddonService {
private boolean isAddon(Feature feature) {
return feature.getName().startsWith(FeatureInstaller.PREFIX)
- && FeatureInstaller.EXTENSION_TYPES.contains(getType(feature.getName()));
+ && FeatureInstaller.ADDON_TYPES.contains(getAddonType(feature.getName()));
}
@Override
@@ -111,24 +118,13 @@ 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_MISC -> "https://www.openhab.org/addons/integrations/" + 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 + "/";
- case FeatureInstaller.EXTENSION_TYPE_UI -> "https://www.openhab.org/addons/ui/" + name + "/";
- default -> null;
- };
+ String format = DOCUMENTATION_URL_FORMATS.get(type);
+ return format == null ? null : String.format(format, name);
}
private Addon getAddon(Feature feature, @Nullable Locale locale) {
String name = getName(feature.getName());
- String type = getType(feature.getName());
+ String type = getAddonType(feature.getName());
String uid = type + Addon.ADDON_SEPARATOR + name;
boolean isInstalled = featuresService.isInstalled(feature);
@@ -159,17 +155,17 @@ public class KarafAddonService implements AddonService {
@Override
public List getTypes(@Nullable Locale locale) {
- return ADDON_TYPES;
+ return AddonType.DEFAULT_TYPES;
}
@Override
public void install(String id) {
- featureInstaller.addAddon(getType(id), getName(id));
+ featureInstaller.addAddon(getAddonType(id), getName(id));
}
@Override
public void uninstall(String id) {
- featureInstaller.removeAddon(getType(id), getName(id));
+ featureInstaller.removeAddon(getAddonType(id), getName(id));
}
@Override
@@ -177,7 +173,7 @@ public class KarafAddonService implements AddonService {
return null;
}
- private String getType(String name) {
+ private String getAddonType(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);
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 7454b58c7..c0fac698f 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -17,9 +17,10 @@
openHAB Core :: Bundles
+ org.openhab.core.addon
+ org.openhab.core.addon.eclipse
org.openhab.core.addon.marketplace
org.openhab.core.addon.marketplace.karaf
- org.openhab.core.addon
org.openhab.core.auth.jaas
org.openhab.core.auth.oauth2client
org.openhab.core.automation
@@ -39,7 +40,6 @@
org.openhab.core
org.openhab.core.audio
org.openhab.core.ephemeris
- org.openhab.core.addon.sample
org.openhab.core.id
org.openhab.core.persistence
org.openhab.core.semantics