Marketplace link resolution

I just did a discovery that frankly shocked me a bit. I found a bug in one of my marketplace add-ons, Thing Type File Provider [4.1.0.0;6.0.0.0), fixed it and released a new version (1.0.1).

To make sure everything went as planned, I installed it from the marketplace on a 5.2.0 test installation, and checked the installed version in the Karaf console. It was the wrong version (1.0.0). I did refreshing etc., and tried again. Consistently, the wrong version (1.0.0) was installed. I then noticed that another marketplace add-on of mine that is at version 1.0.3, was installed at version 1.0.2.

I’ve thought/understood it so that the last link in the post that links to a “valid type” (.jar, .kar here, or .yaml, .json for other types) would be the one that is used. When looking at the marketplace parsing code, that is the logic found there, it overwrites the “resource” variable each time one is found, so it should end up with the last one. I had arranged my posts accordingly, with the newest links last.

I started digging and debugging, and this is what I found: The forum is requested for JSONs with the content, and here is the current content from my updated add-on:

{
    "post_stream": {
        "posts": [
            {
                "id": 956659,
                "name": "Nadar",
                "username": "Nadahar",
                "avatar_template": "/user_avatar/community.openhab.org/nadahar/{size}/44246_2.png",
                "created_at": "2025-12-15T19:25:40.681Z",
                "cooked": "<p>This add-on parses XML files placed in <code>$OPENHAB_CONF/thingtypes</code> and provides the resulting <code>ThingType</code>, <code>ChannelType</code> and <code>ChannelGroupType</code> definitions to the openHAB registries. Use this to make custom or third‑party thing definitions immediately available without waiting for releases, for example to test or add ZWave devices before the definition is available in a release.</p>\n<h2><a name=\"p-956659-quick-start-1\" class=\"anchor\" href=\"#p-956659-quick-start-1\" aria-label=\"Heading link\"></a>Quick start</h2>\n<ol>\n<li>Create the folder if it does not exist:\n<ul>\n<li>Linux/macOS: <code>mkdir -p $OPENHAB_CONF/thingtypes</code></li>\n<li>Windows (PowerShell): <code>mkdir $env:OPENHAB_CONF\\thingtypes</code></li>\n</ul>\n</li>\n<li>Place one or more XML files with Thing definitions in that folder.</li>\n<li>The add‑on will load the definitions and publish them to the registries.</li>\n</ol>\n<h2><a name=\"p-956659-prerequisites-2\" class=\"anchor\" href=\"#p-956659-prerequisites-2\" aria-label=\"Heading link\"></a>Prerequisites</h2>\n<ul>\n<li>Compatible openHAB version: check the add‑on compatibility for your openHAB release.</li>\n<li><code>$OPENHAB_CONF</code> must be defined and reachable by the openHAB process.</li>\n<li>XML files must follow the same syntax as described in the openHAB <a href=\"https://www.openhab.org/docs/developer/bindings/thing-xml.html\">Binding Definitions</a> documentation.</li>\n</ul>\n<h2><a name=\"p-956659-file-format-example-3\" class=\"anchor\" href=\"#p-956659-file-format-example-3\" aria-label=\"Heading link\"></a>File format / Example</h2>\n<p>Save files with <code>.xml</code> extension. Example (very small excerpt):</p>\n<pre data-code-wrap=\"xml\"><code class=\"lang-xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;thing-descriptions&gt;\n  &lt;thing-type id=\"bindingid:device-type\" label=\"Device Label\"&gt;\n    &lt;channels&gt;\n      &lt;channel id=\"switch\" typeId=\"switch\" /&gt;\n    &lt;/channels&gt;\n  &lt;/thing-type&gt;\n&lt;/thing-descriptions&gt;\n</code></pre>\n<p>Place it as:</p>\n<ul>\n<li><code>$OPENHAB_CONF/thingtypes/my-device.xml</code></li>\n</ul>\n<h2><a name=\"p-956659-intended-use-4\" class=\"anchor\" href=\"#p-956659-intended-use-4\" aria-label=\"Heading link\"></a>Intended Use</h2>\n<p>This add-on has been written to solve a challenge when using the <a href=\"https://www.openhab.org/addons/bindings/zwave/\">ZWave binding</a>, but it is not limited to this use. It provides definitions system-wide.</p>\n<p>The challenge when using the ZWave binding is that device definitions must be created in the <a href=\"https://opensmarthouse.org/zwavedatabase\">Z-Wave Device Database</a>, but there’s no readily available way to actually use the resulting XML files. Instead, one must wait for the next release, or use a snapshot build. This is a slow cycle, especially if there’s a need to tweak aspects of the definition after testing.</p>\n<p>Another potential challenge is when running an older version of openHAB, which means that the updated definitions won’t be made available at all, and a snapshot build probably won’t work.</p>\n<p>By installing this add-on and saving the XML files that can be exported from the device database in <code>$OPENHAB_CONF/thingtypes</code>, you can make these definitions available to your system immediately.</p>\n<h2><a name=\"p-956659-behavior-limitations-5\" class=\"anchor\" href=\"#p-956659-behavior-limitations-5\" aria-label=\"Heading link\"></a>Behavior &amp; Limitations</h2>\n<ul>\n<li>This add-on provides definitions system‑wide and can be used by any binding or other system component.</li>\n<li>Lack of priority: openHAB has no built‑in priority between sources. If a binding provides the same <code>ThingTypeUID</code>, you cannot define which source is used.</li>\n<li>ZWave binding: the <a href=\"https://www.openhab.org/addons/bindings/zwave/\">ZWave binding</a> caches device definitions aggressively at startup.<br>\nAdding or changing files at runtime will update openHAB’s registries, but will not affect ZWave binding behavior until openHAB is restarted.</li>\n</ul>\n<h2><a name=\"p-956659-troubleshooting-6\" class=\"anchor\" href=\"#p-956659-troubleshooting-6\" aria-label=\"Heading link\"></a>Troubleshooting</h2>\n<ul>\n<li>Nothing appears after placing files:\n<ul>\n<li>Verify file syntax and extension <code>.xml</code>.</li>\n<li>Check openHAB logs for parsing errors (look for the add‑on name).</li>\n<li>Confirm that <code>$OPENHAB_CONF/thingtypes</code> is readable by openHAB.</li>\n</ul>\n</li>\n<li>Device still not recognized (Z-Wave):\n<ul>\n<li>Restart openHAB to force the ZWave binding to re‑read definitions.</li>\n</ul>\n</li>\n</ul>\n<h2><a name=\"p-956659-changelog-7\" class=\"anchor\" href=\"#p-956659-changelog-7\" aria-label=\"Heading link\"></a>Changelog</h2>\n<h3><a name=\"p-956659-version-101-8\" class=\"anchor\" href=\"#p-956659-version-101-8\" aria-label=\"Heading link\"></a>Version 1.0.1</h3>\n<ul>\n<li>Fix wrong OSGi service property registration that would prevent the add-on from working on some installations.</li>\n</ul>\n<h3><a name=\"p-956659-version-100-9\" class=\"anchor\" href=\"#p-956659-version-100-9\" aria-label=\"Heading link\"></a>Version 1.0.0</h3>\n<ul>\n<li>Slightly refined the logging of parsing errors.</li>\n</ul>\n<h3><a name=\"p-956659-version-100-beta1-10\" class=\"anchor\" href=\"#p-956659-version-100-beta1-10\" aria-label=\"Heading link\"></a>Version 1.0.0-beta1</h3>\n<ul>\n<li>initial release</li>\n</ul>\n<h2><a name=\"p-956659-resources-11\" class=\"anchor\" href=\"#p-956659-resources-11\" aria-label=\"Heading link\"></a>Resources</h2>\n<p><a href=\"https://github.com/Nadahar/openHAB-ThingTypes/releases/download/v1.0.0/org.openhab.io.thingtypes-1.0.0.jar\" class=\"onebox\" target=\"_blank\" rel=\"noopener\">https://github.com/Nadahar/openHAB-ThingTypes/releases/download/v1.0.0/org.openhab.io.thingtypes-1.0.0.jar</a></p>\n<p><a href=\"https://github.com/Nadahar/openHAB-ThingTypes/releases/download/v1.0.1/org.openhab.io.thingtypes-1.0.1.jar\" class=\"onebox\" target=\"_blank\" rel=\"noopener\">https://github.com/Nadahar/openHAB-ThingTypes/releases/download/v1.0.1/org.openhab.io.thingtypes-1.0.1.jar</a></p>\n<aside class=\"onebox githubrepo\" data-onebox-src=\"https://github.com/Nadahar/openHAB-ThingTypes\">\n  <header class=\"source\">\n\n      <a href=\"https://github.com/Nadahar/openHAB-ThingTypes\" target=\"_blank\" rel=\"noopener\">github.com</a>\n  </header>\n\n  <article class=\"onebox-body\">\n    <div class=\"github-row\" data-github-private-repo=\"false\">\n  <img width=\"690\" height=\"344\" src=\"https://opengraph.githubassets.com/ca5a49cc95be13a3cd38fe0bc34e8327/Nadahar/openHAB-ThingTypes\" class=\"thumbnail\">\n\n  <h3><a href=\"https://github.com/Nadahar/openHAB-ThingTypes\" target=\"_blank\" rel=\"noopener\">GitHub - Nadahar/openHAB-ThingTypes: openHAB Thing Types Service</a></h3>\n\n    <p><span class=\"github-repo-description\">openHAB Thing Types Service</span></p>\n</div>\n\n  </article>\n\n  <div class=\"onebox-metadata\">\n    \n    \n  </div>\n\n  <div style=\"clear: both\"></div>\n</aside>\n",
                "post_number": 1,
                "post_type": 1,
                "posts_count": 1,
                "updated_at": "2026-07-17T23:43:28.183Z",
                "reply_count": 0,
                "reply_to_post_number": null,
                "quote_count": 0,
                "incoming_link_count": 21,
                "reads": 51,
                "readers_count": 50,
                "score": 115.2,
                "yours": false,
                "topic_id": 167543,
                "topic_slug": "thing-type-file-provider-4-1-0-0-6-0-0-0",
                "display_username": "Nadar",
                "primary_group_name": null,
                "flair_name": null,
                "flair_url": null,
                "flair_bg_color": null,
                "flair_color": null,
                "flair_group_id": null,
                "badges_granted": [],
                "version": 5,
                "can_edit": false,
                "can_delete": false,
                "can_recover": false,
                "can_see_hidden_post": false,
                "can_wiki": false,
                "link_counts": [
                    {
                        "url": "https://github.com/Nadahar/openHAB-ThingTypes",
                        "internal": false,
                        "reflection": false,
                        "title": "GitHub - Nadahar/openHAB-ThingTypes: openHAB Thing Types Service",
                        "clicks": 6
                    },
                    {
                        "url": "https://opensmarthouse.org/zwavedatabase",
                        "internal": false,
                        "reflection": false,
                        "title": "OpenSmartHouse Z-Wave Device Database",
                        "clicks": 2
                    },
                    {
                        "url": "https://www.openhab.org/addons/bindings/zwave/",
                        "internal": false,
                        "reflection": false,
                        "title": "ZWave - Bindings | openHAB",
                        "clicks": 0
                    },
                    {
                        "url": "https://www.openhab.org/docs/developer/bindings/thing-xml.html",
                        "internal": false,
                        "reflection": false,
                        "title": "Thing Descriptions | openHAB",
                        "clicks": 0
                    },
                    {
                        "url": "https://github.com/Nadahar/openHAB-ThingTypes/releases/download/v1.0.1/org.openhab.io.thingtypes-1.0.1.jar",
                        "internal": false,
                        "reflection": false,
                        "clicks": 0
                    },
                    {
                        "url": "https://github.com/Nadahar/openHAB-ThingTypes/releases/download/v1.0.0/org.openhab.io.thingtypes-1.0.0.jar",
                        "internal": false,
                        "reflection": false,
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/can-i-add-a-new-z-wave-device-xml-to-the-local-z-wave-device-database/141605/11",
                        "internal": true,
                        "reflection": true,
                        "title": "Can I add a new Z-Wave device XML to the local Z-Wave device database?",
                        "clicks": 4
                    },
                    {
                        "url": "https://community.openhab.org/t/the-state-of-the-z-wave-binding/167507/18",
                        "internal": true,
                        "reflection": true,
                        "title": "The state of the Z-Wave binding",
                        "clicks": 1
                    },
                    {
                        "url": "https://community.openhab.org/t/review-request-for-76592-zwn4016-enbrighten-z-wave-800-series-in-wall-smart-switch/167719/3",
                        "internal": true,
                        "reflection": true,
                        "title": "Review request for 76592/ZWN4016 Enbrighten Z-Wave 800 Series In-Wall Smart Switch",
                        "clicks": 1
                    },
                    {
                        "url": "https://community.openhab.org/t/openhab-5-1-milestone-discussion/166385/197",
                        "internal": true,
                        "reflection": true,
                        "title": "openHAB 5.1 Milestone discussion",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/z-wave-thing-is-missing-supported-group-associations-opensmarthouse-db-is-too/169817/4",
                        "internal": true,
                        "reflection": true,
                        "title": "Z-Wave thing is missing supported group associations. OpenSmartHouse DB is too",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/channel-templates/169718/15",
                        "internal": true,
                        "reflection": true,
                        "title": "Channel Templates",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/ultrapro-z-wave-plus-long-range-in-wall-smart-dimmer-no-channels-found/169276/5",
                        "internal": true,
                        "reflection": true,
                        "title": "UltraPro Z-Wave Plus Long Range in-Wall Smart Dimmer - no channels found",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/zwave-z-stick-sdk-issue-with-oh-z-wave-binding/161582/22",
                        "internal": true,
                        "reflection": true,
                        "title": "Zwave Z-stick SDK issue with OH Z-wave binding",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/zoos-zen52-lr-double-relay-page-widget-does-not-respond-to-relay-switch-change/167564/5",
                        "internal": true,
                        "reflection": true,
                        "title": "Zoos Zen52 LR Double Relay Page Widget does not respond to relay switch change",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/provide-z-wave-device-descriptions-from-local-file/167563",
                        "internal": true,
                        "reflection": true,
                        "title": "Provide Z-Wave device descriptions from local file",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/is-the-opensmarthouse-z-wave-device-database-still-used-unable-to-get-editor-access/169421/11",
                        "internal": true,
                        "reflection": true,
                        "title": "Is the OpenSmartHouse Z-Wave Device Database still used? Unable to get editor access",
                        "clicks": 0
                    },
                    {
                        "url": "https://community.openhab.org/t/zoos-zen52-lr-double-relay-page-widget-does-not-respond-to-relay-switch-change/167564/35",
                        "internal": true,
                        "reflection": true,
                        "title": "Zoos Zen52 LR Double Relay Page Widget does not respond to relay switch change",
                        "clicks": 0
                    }
                ],
                "read": true,
                "user_title": null,
                "bookmarked": false,
                "actions_summary": [],
                "moderator": false,
                "admin": false,
                "staff": false,
                "user_id": 36689,
                "hidden": false,
                "trust_level": 4,
                "deleted_at": null,
                "user_deleted": false,
                "edit_reason": null,
                "can_view_edit_history": false,
                "wiki": false,
                "post_url": "/t/thing-type-file-provider-4-1-0-0-6-0-0-0/167543/1",
                "reactions": [],
                "current_user_reaction": null,
                "reaction_users_count": 0,
                "current_user_used_main_reaction": false,
                "can_accept_answer": false,
                "can_unaccept_answer": false,
                "accepted_answer": false,
                "topic_accepted_answer": null,
                "can_vote": false
            }
        ],
        "stream": [
            956659
        ]
    },
    "timeline_lookup": [
        [
            1,
            214
        ]
    ],
    "tags": [
        {
            "id": 4394,
            "name": "published",
            "slug": "published"
        },
        {
            "id": 1194,
            "name": "stable",
            "slug": "stable"
        },
        {
            "id": 4395,
            "name": "misc",
            "slug": "misc"
        }
    ],
    "tags_descriptions": {},
    "fancy_title": "Thing Type File Provider [4.1.0.0;6.0.0.0)",
    "id": 167543,
    "title": "Thing Type File Provider [4.1.0.0;6.0.0.0)",
    "posts_count": 1,
    "created_at": "2025-12-15T19:25:40.591Z",
    "views": 133,
    "reply_count": 0,
    "like_count": 0,
    "last_posted_at": "2025-12-15T19:25:40.681Z",
    "visible": true,
    "closed": false,
    "archived": false,
    "has_summary": false,
    "archetype": "regular",
    "slug": "thing-type-file-provider-4-1-0-0-6-0-0-0",
    "category_id": 73,
    "word_count": 592,
    "deleted_at": null,
    "user_id": 36689,
    "featured_link": null,
    "pinned_globally": false,
    "pinned_at": null,
    "pinned_until": null,
    "image_url": null,
    "slow_mode_seconds": 0,
    "draft": null,
    "draft_key": "topic_167543",
    "draft_sequence": null,
    "unpinned": null,
    "pinned": false,
    "current_post_number": 1,
    "highest_post_number": 1,
    "deleted_by": null,
    "actions_summary": [
        {
            "id": 4,
            "count": 0,
            "hidden": false,
            "can_act": false
        },
        {
            "id": 8,
            "count": 0,
            "hidden": false,
            "can_act": false
        },
        {
            "id": 10,
            "count": 0,
            "hidden": false,
            "can_act": false
        },
        {
            "id": 7,
            "count": 0,
            "hidden": false,
            "can_act": false
        }
    ],
    "chunk_size": 20,
    "bookmarked": false,
    "topic_timer": null,
    "message_bus_last_id": 2,
    "participant_count": 1,
    "show_read_indicator": false,
    "thumbnails": null,
    "slow_mode_enabled_until": null,
    "valid_reactions": [
        "heart",
        "+1",
        "laughing",
        "open_mouth",
        "clap",
        "confetti_ball",
        "hugs"
    ],
    "can_create_shared_issue": false,
    "shared_issue_visible": false,
    "can_vote": false,
    "vote_count": 0,
    "user_voted": false,
    "discourse_zendesk_plugin_zendesk_id": null,
    "discourse_zendesk_plugin_zendesk_url": "https://your-url.zendesk.com/agent/tickets/",
    "details": {
        "can_edit": false,
        "notification_level": 1,
        "created_by": {
            "id": 36689,
            "username": "Nadahar",
            "name": "Nadar",
            "avatar_template": "/user_avatar/community.openhab.org/nadahar/{size}/44246_2.png"
        },
        "last_poster": {
            "id": 36689,
            "username": "Nadahar",
            "name": "Nadar",
            "avatar_template": "/user_avatar/community.openhab.org/nadahar/{size}/44246_2.png"
        },
    },
    "bookmarks": []
}

Basically, the raw text from the post itself is stored in the cooked property. Various data about the post, or extracted from the post, populate the other properties. The marketplace parsing code doesn’t however parse through cookedto find the links, because Discourse has already done that. Instead, link_counts is used, which contains an array of links, where the last (valid one) is used.

But, notice that link_counts aren’t in chronological order, which I always thought they were. Insttead, they seem to be sorted descending by the number of click combined with some other criteria. That basically makes it completely “random” which one will be used.

I’m sure that I have debugged this before and found it to work, so I’m not speculating that perhaps, if all links have 0 clicks, they are in chronological order, but as soon as some URLs have “registered clicks”, that’s no longer the case.

The end result is that you can’t leave links to previous versions of the add-on in the marketplace post, or they might be picked as the “current” one.

I’ll try to find a way to make which link is picked predictabe, but that won’t help for older versions of OH anyway. So, the morale of the story must in a way be: A marketplace post can only have one link that is to a “resource”, that is, that links to a file with an extension that matches the type of add-on.

Looks to me like they are separated into external (first) and internal (second) links and then those categories are sorted by clicks.

Regardless of the actual sorting, picking the last one won’t give you the most recent version even if it’s the bottom link…

I’ve added a fix to this PR