Installing KAR add-ons through the addons folder

I’m working on trying to make add-ons versioned. As a consequence, I’m in contact with most of the code related to add-ons in Core.

I’m currently trying to understand KAR add-ons. This is what I’ve found so far:

  • Official add-ons are handled using Karaf features, which is a completely different way from how other add-ons are handled, making it not a focus for me at this time.
  • Third party JSON add-ons uses KAR add-ons, which are handled by JsonAddonService. I’ve not quite gotten to the bottom of how that is all handled, but it seems to work and doesn’t suffer from the problem I’m currently facing.
  • Community marketplace add-ons also support KAR I think, but they don’t suffer from the problem here either.

The problem is when it comes to the addons folder. You can drop JAR files there, and they are installed. When I try to install a KAR file there, it doesn’t work. What happens is that the file itself is picked up and the bundles inside the KAR seems to be installed. But, it doesn’t show up as an add-on. The reason is that to show up as an add-on, OH-INF\addon\addon.xml must be parsed, and I can’t find any mechanism that currently does that.

JarFileAddonService handles this for JAR files, but that’s simpler because a JAR file only contains a single bundle. Thus, the “filtering criteria” for JarFileAddonService is that the bundle’s “location” starts with file: (I’ve also added http: and https: so that add-ons installed as bundles from Karaf shows up). The bundles installed by the KAR file I’ve tested (I don’t know if this is always true for KAR files) and up having a mvn: type location. I can’t make JarFileAddonService pick up bundles with mvn: locations, because that’s also how all the official add-ons are registered. Including mvn: would thus cause all official add-ons to show up twice under add-ons.

I’ve searched the forum and read through the documentation, but I find very little information. There are some references to installing KAR add-ons on the forum, but they are mostly very old and provides little information relevant here. It does seem to have been something that was done once upon a time at least. The documentation doesn’t mention it at all, it only talks about JARs. But, the fact that KAR files are picked up and the bundles are installed does indicate that it’s “supposed to” work, even if they fail to register as add-ons, while the lack of documentation suggests the opposite.

So, what is it: Is this supposed to work or not?

Show up where? It is not going to show up in MainUI if that’s what you mean. But you should see it listed as a bundle in the karaf console.

This is the way it’s always worked as far as I can remember. Whether it’s supposed to work like that or not :person_shrugging:

Show up where an add-on should: in MainUI, in the REST API under /addons, as a choice when you want to add a new Thing (if it’s a binding) etc. Yes, the bundles show up and are started, but OH doesn’t “consider them add-ons”, so functionality will be missing.

I’m just trying to figure this out, if you’re saying that this is how it’s always been, that is helpful. The question is if I should try to fix this - all that’s really needed is to find a way to differentiate them from the official add-ons. If I can tell them apart, I can get them registered as add-ons.

Do you have any feature named openhab-xyz-binding or so in your KAR file? Can you confirm if features:list contain your feature in general? I think I do have KARs in connectorio-addons which are recognized properly by openHAB 4.x.

It would be very nice if add-ons installed this way were correctly registered.

1 Like

It doesn’t seem like it. I simply installed the SmartHome/J Tuya binding and copied the KAR from userdata/marketplace/kar (and then uninstalled it again). It seems hard to get a direct download for the SmartHome/J add-ons.

I should probably inspect and test other KARs as well - suggestions for where to find them are appreciated.

I can imagine that a KAR with a “feature” might work, since it would probably be picked up by the mechanism used for the official add-ons - which is based on Karaf features. So, maybe what I need to do is to exclude bundles that are part of any “feature”, and then register the rest. I’m not sure how easy that is to do though, it seems like I would have to enumerate all features and all the bundles in them to know - and “features” are only available when running under Karaf, so it would also have to work when they aren’t available.

I observed similar issue as you, and my workaround was using official feature name, as to be fair, there is nothing preventing you from doing that.

I made a test which:

  1. Install KAR file with addon.
  2. Call OH API to check if addon is recognized (connectorio-addons/itests/org.connectorio.addons.itest/src/main/java/org/connectorio/addons/itest/OfflineKarInstallationTest.java at master · ConnectorIO/connectorio-addons · GitHub)
  3. Install addon by name (i.e. binding-xyz).

Relevant part is making KAR contain valid feature definitions. Depending on karaf tooling plugin configuration resulting KAR may contain only one big feature with all dependencies found. I instruct plugin to:

  1. Aggregate features: connectorio-addons/kars/pom.xml at master · ConnectorIO/connectorio-addons · GitHub
  2. Do not install KAR by default: connectorio-addons/kars/pom.xml at master · ConnectorIO/connectorio-addons · GitHub (so user can decide if he wants to use addon).
  3. Assembly KAR using feature descriptors: connectorio-addons/kars/pom.xml at master · ConnectorIO/connectorio-addons · GitHub

I know whole thing is divided across multiple places, so its hard to follow. Hope that some of these hints will help you navigating over the problem.

Cheers,
Łukasz

We don’t use openhab-*-binding feature names with Marketplace entries. The reason is that when you install a KAR via the Marketplace you end up with two addon entries in the add-on list: the market place entry and the Karaf feature.

Yes, that goes to the heart of what I’m trying to figure out - how to register add-ons one, and only one, time. Honestly, I suspect that this is done way too complicated. Instead of KarafAddonService, JarAddonService and EclipseAddonService, there should only be BundleAddonService - which would register all ACTIVE bundles that have a valid OH-INF\addon\addon.xml definition as add-ons. JsonAddonService and CommunityMarketplaceAddonService should then keep their hands of any bundles, and only handle non-bundle add-ons.

I think that would make this much cleaner and simpler, with no double or missing registrations, but it would change the existing “organization” how which add-ons have what “source” (in the UI) and possible also “provisioned by” (I don’t remember exactly how MainUI determintes this, but it’s already wrong in many circumstances). It might also make it harder to distinguish between official and non-official add-ons, I’m not quite sure. I suspect that what makes an add-on “official” today may simply be that it’s a “Karaf feature”.

Edit: That wouldn’t work, because the AddonServices also handle installation and uninstallation. I was thinking solely about providing the “add-on registration”. I’m not sure how at the moment, but I think it should be organized somewhat differently so you wouldn’t get these dilemmas.

About the only reason such a distinction needs to be made by end users is when searching for/installing/updating the add-ons. Once installed there really shouldn’t be anything different in the way the end user interacts with that add-on.

But, given that the distinction between them has to already be there before the add-on is installed in the first place, I wonder if this matters. The user knows if they installed it from the list of official add-ons, from the marketplace, or by dropping the jar/kar file into the addons folder. So they know the upgrade process will be different based on how they installed them.

Beyond that there shouldn’t be any differences. That’s the desired end state, from the end user’s perspective.

The problem, I think (I don’t have all the details clear in my head right now, there are too many moving parts here to be assertive), is that the same mechanism determines how they are shown in the “Add-on Store”, so that the distinction is needed to present them separately there. I think this is also used to set the “verified author” status, basically, every official add-ons are “verified” while all the rest aren’t.

But that distinction is already there. Official add-ons are listed in one place. Marketplace add-ons are listed in a separate section. Jar/Kar files are listed nowhere (but after installation they should appear in all the other places in MainUI where an official or marketplace installed add-on does for Thing discovery, log level configuration, etc.).

That’s correct. As of right now, if the add-ons didn’t come from the openHAB distro itself the authors are unverified. All distro add-ons are by definition by verified authors. All other add-ons are by definition by not verified authors. It’s no more complicated than that.

There may be an idea somewhere to expand “verified authors” or something but right now only those add-ons that are part of the openHAB project, whose code resides in the openhab/openhab-addons repo are “official” and by “verified authors”. Everything else is unofficial by unverified authors.

Obviously I don’t know anything about the code. But conceptually from the end user’s perspective it’s should be pretty straight forward.

  1. Once installed all add-ons no matter how they are installed should work the same (except for removal). Outside the Add-on Store, there should be no distinction between them.
  2. If it’s an official add-on, installation/uninstallation is done by choosing the add-on from the Add-on store.
  3. If it’s a marketplace add-on, installation/uninstallation is done by choosing the add-on from the Add-on store. Only difference from 2 is that the add-on will be listed under the Marketplace section.
  4. If it’s some other third party add-on it’s installed by dropping the Jar/Kar file in the add-ons folder.

Upgrades is one place where there is a distinction though I don’t think that the distinction needs to be managed inside of OH core. Right now, clear the cache, which happens during an upgrade of OH core, will cause the official add-ons to be updated.

Clear the cache will also cause the marketplace add-ons to be completely removed and need to be manually reinstalled, though this might be a bug. I can’t get a straight answer on whether this is by design or not.

Jar/Kar files left in the addons folder could cause OH to crash and fail to come up, but these are left untouched (see Clean up addons folder on upgrade · Issue #1574 · openhab/openhab-distro · GitHub).

It’s there today because the AddonServices are the way they are. I haven’t been able to test it yet, because I don’t have a KAR file with a feature definition, but I’m fairly sure that if you make such a KAR, it will show up as “an official add-on”.

In short, I think the distinction between official add-ons and other add-ons is “artificial” in that any add-on presented to OH as a “Karaf feature” will be shown, in the add-on store, as “official” and with a verified author.

What I was trying to say is that the existing organization is problematic because of its “artificial nature”, where it’s difficult to register all add-ons properly if you only want to present them once. The reason is that there’s no “real” information available to tell them apart, so you rely on “circumstantial evidence” like whether it’s a Karaf feature or not.

If I am to try to reorganize this so that all add-ons are registered, I would have to find some other way to distinguish them, or it wouldn’t be possible for the add-on store to distinguish between them and present them in different categories, with different “verified” status.

It’s not “by design”, but highly likely to happen the way the code is written. I think I understand fairly well why this is as it is, and how to do it “better”.

I’m not keen on setting up a build environment for KARs just to test this. It seems that the KARs you refer to is locked behind a registration, and probably payment, which I’m not going to do to test this. I’m still hoping there is a ready-made KAR out there, with “feature definition”, that somebody can point me to.

Doesn’t running

mvn clean install karaf:kar -pl :org.openhab.binding.astro

create a kar for you?
It should work on any binding.

It creates a KAR file, but not one that seems to work if dropped into addons (it doesn’t contain a feature descriptor either):

openhab> org.apache.karaf.features.internal.util.MultiException: Error:
        Error downloading mvn:de.focus-shift/jollyday-core/1.5.4
        Error downloading mvn:de.focus-shift/jollyday-jackson/1.5.4
        at org.apache.karaf.features.internal.download.impl.MavenDownloadManager$MavenDownloader.<init>(MavenDownloadManager.java:91)
        at org.apache.karaf.features.internal.download.impl.MavenDownloadManager.createDownloader(MavenDownloadManager.java:72)
        at org.apache.karaf.features.internal.region.Subsystem.downloadBundles(Subsystem.java:474)
        at org.apache.karaf.features.internal.region.Subsystem.downloadBundles(Subsystem.java:469)
        at org.apache.karaf.features.internal.region.SubsystemResolver.resolve(SubsystemResolver.java:223)
        at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:399)
        at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1069)
        at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:1004)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
        Suppressed: java.io.IOException: Error downloading mvn:de.focus-shift/jollyday-core/1.5.4
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:77)
                at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
                at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
                at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
                ... 3 more
        Caused by: java.io.IOException: Error resolving artifact de.focus-shift:jollyday-core:jar:1.5.4: [Could not find artifact de.focus-shift:jollyday-core:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)]
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.configureIOException(AetherBasedResolver.java:803)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:774)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:657)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:598)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:565)
                at org.apache.karaf.features.internal.download.impl.MavenDownloadTask.download(MavenDownloadTask.java:52)
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:60)
                ... 6 more
                Suppressed: shaded.org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact de.focus-shift:jollyday-core:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)
                        at shaded.org.eclipse.aether.connector.basic.ArtifactTransportListener.transferFailed(ArtifactTransportListener.java:48)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:401)
                        at shaded.org.eclipse.aether.util.concurrency.RunnableErrorForwarder.lambda$wrap$0(RunnableErrorForwarder.java:73)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$DirectExecutor.execute(BasicRepositoryConnector.java:669)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector.get(BasicRepositoryConnector.java:290)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads(DefaultArtifactResolver.java:520)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:408)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                        at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                        at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                        ... 11 more
        Caused by: shaded.org.eclipse.aether.resolution.ArtifactResolutionException: Error resolving artifact de.focus-shift:jollyday-core:jar:1.5.4
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:431)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                ... 11 more
        Suppressed: java.io.IOException: Error downloading mvn:de.focus-shift/jollyday-jackson/1.5.4
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:77)
                at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
                at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
                at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
                ... 3 more
        Caused by: java.io.IOException: Error resolving artifact de.focus-shift:jollyday-jackson:jar:1.5.4: [Could not find artifact de.focus-shift:jollyday-jackson:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)]
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.configureIOException(AetherBasedResolver.java:803)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:774)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:657)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:598)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:565)
                at org.apache.karaf.features.internal.download.impl.MavenDownloadTask.download(MavenDownloadTask.java:52)
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:60)
                ... 6 more
                Suppressed: shaded.org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact de.focus-shift:jollyday-jackson:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)
                        at shaded.org.eclipse.aether.connector.basic.ArtifactTransportListener.transferFailed(ArtifactTransportListener.java:48)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:401)
                        at shaded.org.eclipse.aether.util.concurrency.RunnableErrorForwarder.lambda$wrap$0(RunnableErrorForwarder.java:73)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$DirectExecutor.execute(BasicRepositoryConnector.java:669)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector.get(BasicRepositoryConnector.java:290)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads(DefaultArtifactResolver.java:520)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:408)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                        at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                        at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                        ... 11 more
        Caused by: shaded.org.eclipse.aether.resolution.ArtifactResolutionException: Error resolving artifact de.focus-shift:jollyday-jackson:jar:1.5.4
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:431)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                ... 11 more
org.apache.karaf.features.internal.util.MultiException: Error:
        Error downloading mvn:de.focus-shift/jollyday-core/1.5.4
        Error downloading mvn:de.focus-shift/jollyday-jackson/1.5.4
        at org.apache.karaf.features.internal.download.impl.MavenDownloadManager$MavenDownloader.<init>(MavenDownloadManager.java:91)
        at org.apache.karaf.features.internal.download.impl.MavenDownloadManager.createDownloader(MavenDownloadManager.java:72)
        at org.apache.karaf.features.internal.region.Subsystem.downloadBundles(Subsystem.java:474)
        at org.apache.karaf.features.internal.region.Subsystem.downloadBundles(Subsystem.java:469)
        at org.apache.karaf.features.internal.region.SubsystemResolver.resolve(SubsystemResolver.java:223)
        at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:399)
        at org.apache.karaf.features.internal.service.Deployer.handlePrerequisites(Deployer.java:1121)
        at org.apache.karaf.features.internal.service.Deployer.deploy(Deployer.java:394)
        at org.apache.karaf.features.internal.service.FeaturesServiceImpl.doProvision(FeaturesServiceImpl.java:1069)
        at org.apache.karaf.features.internal.service.FeaturesServiceImpl.lambda$doProvisionInThread$13(FeaturesServiceImpl.java:1004)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
        Suppressed: java.io.IOException: Error downloading mvn:de.focus-shift/jollyday-core/1.5.4
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:77)
                at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
                at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
                at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
                ... 3 more
        Caused by: java.io.IOException: Error resolving artifact de.focus-shift:jollyday-core:jar:1.5.4: [Could not find artifact de.focus-shift:jollyday-core:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)]
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.configureIOException(AetherBasedResolver.java:803)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:774)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:657)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:598)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:565)
                at org.apache.karaf.features.internal.download.impl.MavenDownloadTask.download(MavenDownloadTask.java:52)
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:60)
                ... 6 more
                Suppressed: shaded.org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact de.focus-shift:jollyday-core:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)
                        at shaded.org.eclipse.aether.connector.basic.ArtifactTransportListener.transferFailed(ArtifactTransportListener.java:48)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:401)
                        at shaded.org.eclipse.aether.util.concurrency.RunnableErrorForwarder.lambda$wrap$0(RunnableErrorForwarder.java:73)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$DirectExecutor.execute(BasicRepositoryConnector.java:669)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector.get(BasicRepositoryConnector.java:290)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads(DefaultArtifactResolver.java:520)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:408)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                        at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                        at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                        ... 11 more
        Caused by: shaded.org.eclipse.aether.resolution.ArtifactResolutionException: Error resolving artifact de.focus-shift:jollyday-core:jar:1.5.4
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:431)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                ... 11 more
        Suppressed: java.io.IOException: Error downloading mvn:de.focus-shift/jollyday-jackson/1.5.4
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:77)
                at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
                at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
                at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
                ... 3 more
        Caused by: java.io.IOException: Error resolving artifact de.focus-shift:jollyday-jackson:jar:1.5.4: [Could not find artifact de.focus-shift:jollyday-jackson:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)]
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.configureIOException(AetherBasedResolver.java:803)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:774)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:657)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:598)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:565)
                at org.apache.karaf.features.internal.download.impl.MavenDownloadTask.download(MavenDownloadTask.java:52)
                at org.apache.karaf.features.internal.download.impl.AbstractRetryableDownloadTask.run(AbstractRetryableDownloadTask.java:60)
                ... 6 more
                Suppressed: shaded.org.eclipse.aether.transfer.ArtifactNotFoundException: Could not find artifact de.focus-shift:jollyday-jackson:jar:1.5.4 in openhab (https://openhab.jfrog.io/openhab/libs-snapshot/)
                        at shaded.org.eclipse.aether.connector.basic.ArtifactTransportListener.transferFailed(ArtifactTransportListener.java:48)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$TaskRunner.run(BasicRepositoryConnector.java:401)
                        at shaded.org.eclipse.aether.util.concurrency.RunnableErrorForwarder.lambda$wrap$0(RunnableErrorForwarder.java:73)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector$DirectExecutor.execute(BasicRepositoryConnector.java:669)
                        at shaded.org.eclipse.aether.connector.basic.BasicRepositoryConnector.get(BasicRepositoryConnector.java:290)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads(DefaultArtifactResolver.java:520)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:408)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                        at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                        at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                        at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                        ... 11 more
        Caused by: shaded.org.eclipse.aether.resolution.ArtifactResolutionException: Error resolving artifact de.focus-shift:jollyday-jackson:jar:1.5.4
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve(DefaultArtifactResolver.java:431)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts(DefaultArtifactResolver.java:235)
                at shaded.org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact(DefaultArtifactResolver.java:212)
                at shaded.org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact(DefaultRepositorySystem.java:272)
                at org.ops4j.pax.url.mvn.internal.AetherBasedResolver.resolve(AetherBasedResolver.java:767)
                ... 11 more```

I really don’t know anything about how KARs work, which is why I’m fumbling a bit here. But, I understand a little bit more now: The Tuya KAR does have a feature definition:

<?xml version="1.0" encoding="UTF-8"?>
<features name="org.smarthomej.binding.tuya-5.0.0-SNAPSHOT" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
	<feature name="smarthomej-binding-tuya" description="Tuya Binding" version="5.0.0-SNAPSHOT">
		<feature>openhab-runtime-base</feature>
		<feature>openhab.tp-httpclient</feature>
		<feature>openhab.tp-netty</feature>
		<bundle dependency="true">mvn:org.smarthomej.addons.bundles/org.smarthomej.commons/5.0.0-SNAPSHOT</bundle>
		<bundle start-level="80">mvn:org.smarthomej.addons.bundles/org.smarthomej.binding.tuya/5.0.0-SNAPSHOT</bundle>
	</feature>
</features>

I creates a feature called “smarthomej-binding-tuya” that is installed in Karaf when the KAR is dropped in addons. But, it isn’t picked up because KarafAddonService contains this:

    private boolean isAddon(Feature feature) {
        return feature.getName().startsWith(FeatureInstaller.PREFIX)
                && FeatureInstaller.ADDON_TYPES.contains(getAddonType(feature.getName()));
    }

FeatureInstaller.PREFIX is defined as:

    public static final String PREFIX = "openhab-";

…and ADDON_TYPES is:

    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");

So, for a “feature” to be registered as an add-on, the feature name must begin with openhab-automation, openhab-binding, openhab-misc etc.

This is then what “designates” an “official” add-on, every add-on registered by KarafAddonService is assigned author “openHAB”, is verified, etc. Features not matching the above criteria aren’t just not considered “official”, they aren’t registered at all.

This explains why KARs must “fake being official” to work, as mentioned above.

It is beyond my knowledge, but here is another link that may help figuring this out: How to build kar files for marketplace that is compatible with milestone and SNAPSHOT builds

1 Like

All the sources I have linked are released under more permissive license than openHAB itself. KARs are also distributed via https://repository.connectorio.cloud, they are available for free and without registration. They were initially published via wordpress site which forced registration, but this system is gone for approximately 2 years.
Anyhow - I do not distribute KARs via marketplace because I have multiple builds which makes it hard to keep all the links up. If someone wants to install them can use old fashion way - download and copy into addons folder.
Note given above about OH upgrade is very valid, if you do upgrade you may need to remove KARs, cause they may cause boot failures.
Note, you can add above repository as an additional maven remote repository (see org.ops4j.pax.url.mvn.cfg file) and then install connectorio addons via two commands features:repo-add mvn:… and feature:install openhab-xyz-binding, so you do not even need to download KAR. :slight_smile:
Anyhow, these are features documented for Apache Karaf, but not advertised by openHAB.

Don’t get me wrong, I’m not criticizing or otherwise expressing an opinion about how connectorio does things. I’m just too deep into a lot of other details to sit down and study all of it so that I can find what I need to test one of the KARs. I downloaded this, which is a KAR, but it seems to be without any content. I just don’t know where to look, there are a lot of files in the repo. I just need some file(s) which I can use to study how OH processes.

I still have a quite limited understanding of KARs, but I do see that there are lots of potential for incompatibilities. With the detailed version requirements for dependencies used by OH add-ons by default, and OH itself constantly bumping the dependency versions in Core, it almost takes a miracle to make things work. I thought some of the point with OSGi was to avoid “dependency hell”, but I must be missing something, because this is quite bad. Maybe the “features” should be defined with much “looser” version requirements, but it’s hard to predict what future versions will be compatible for any given artifact - and it’s also a lot of work to verify which past versions work. I thought maybe the point with KARs was that you could bundle the dependencies you need in the file, and that way be independent of OHs dependencies, but that would probably mean that you couldn’t depend on any of the “OH features”.

Regardless, when it comes to booting OH with incompatible KARs, maybe there should be some switch/command line option that disabled the addons folder altogether and that would be enabled after an upgrade, until something could be checked/verified. But, it might be difficult to actually verify if they will load without just trying it - which will then potentially crash OH. I don’t know the exact solution, but it should be possible to suspend loading from the addons folder until “the rest of the upgrade process” has been completed, at the very least.

Karaf has quite a few possibilities it seems, but isn’t exactly user-friendly or “well documented”, so I don’t find it strange that not all of these things are “suggested” to OH users. You can probably also do feature:install <URL to KAR file>, at least you can do this with bundles. But, bundles installed this way won’t be properly installed as add-ons, which is some of what I’m trying to find a solution to.