Extend to 1000 the possible sub-widgets number in a sitemap frame/page#5466
Extend to 1000 the possible sub-widgets number in a sitemap frame/page#5466lolodomo wants to merge 1 commit intoopenhab:mainfrom
Conversation
|
@holgerfriedrich @wborn : looks like the build system is no more working. All my PRs are impacted. This is something new since today I believe. |
|
I am looking into this. Apparently one of our allowed GH actions is no longer listed in the configuration. Before adding it again, let me check something...... |
|
I tightened the CI security a bit (triggered by the latest axios supply chain attack) and thought we removed this action as we use the Maven wrapper instead nowadays? 🤔 |
The previous limit was 100. An error will also be logged in case of detection of more than 1000 widgets in a sitemap frame/page when the page is opened. Closes openhab#5434 Signed-off-by: Laurent Garnier <lg.hc@free.fr>
c6b390b to
adb119c
Compare
There was a problem hiding this comment.
Pull request overview
Updates the sitemap widget ID encoding to support up to 1000 widgets per level (by moving from 2-digit to 3-digit per-depth encoding) and adds logging when the limit is exceeded, aligning core sitemap navigation with the constraints described in issue #5434.
Changes:
- Increase widget ID segment width from 2 to 3 digits and adjust parsing accordingly.
- Add an error log when a widget index exceeds the supported per-level limit.
- Update REST sitemap test constants to reflect the new 3-digit widget ID format.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/items/ItemUIRegistryImpl.java | Implements 3-digit widgetId encoding/decoding and logs when per-level widget count exceeds the supported maximum. |
| bundles/org.openhab.core.io.rest.sitemap/src/test/java/org/openhab/core/io/rest/sitemap/internal/SitemapResourceTest.java | Updates expected widgetId strings to 3 digits. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| int widgetID = Integer.parseInt(id.substring(0, WIDGET_ID_CODING_SIZE)); | ||
| if (widgetID < sitemap.getWidgets().size()) { | ||
| w = sitemap.getWidgets().get(widgetID); | ||
| for (int i = 2; i < id.length(); i += 2) { | ||
| int childWidgetID = Integer.parseInt(id.substring(i, i + 2)); | ||
| for (int i = WIDGET_ID_CODING_SIZE; i < id.length(); i += WIDGET_ID_CODING_SIZE) { | ||
| int childWidgetID = Integer.parseInt(id.substring(i, i + WIDGET_ID_CODING_SIZE)); | ||
| if (childWidgetID < ((LinkableWidget) w).getWidgets().size()) { | ||
| w = ((LinkableWidget) w).getWidgets().get(childWidgetID); | ||
| } |
There was a problem hiding this comment.
getWidget(Sitemap, String) now assumes the widgetId has at least WIDGET_ID_CODING_SIZE chars and that every segment is present. Requests using legacy 2-digit IDs (e.g. existing bookmarks) or malformed IDs can trigger StringIndexOutOfBoundsException (substring) or IndexOutOfBoundsException (negative values pass the < size check and then get(-1)), resulting in 500s. Please validate length/segment boundaries (>=0 and < size), ensure w is a LinkableWidget before casting, and return null for invalid paths; consider accepting the legacy 2-digit encoding for backward compatibility.
| while (w.getParent() instanceof LinkableWidget parent) { | ||
| String index = String.valueOf(parent.getWidgets().indexOf(w)); | ||
| if (index.length() == 1) { | ||
| index = "0" + index; // make it two digits | ||
| } | ||
| int num = parent.getWidgets().indexOf(w); | ||
| error |= (num >= MAX_SUPPORTED_CHILDREN); | ||
| String index = String.format(WIDGET_ID_CODING_FORMAT, num); | ||
| id = index + id; | ||
| w = parent; |
There was a problem hiding this comment.
When num >= MAX_SUPPORTED_CHILDREN, String.format(WIDGET_ID_CODING_FORMAT, num) produces more than WIDGET_ID_CODING_SIZE digits (e.g. 1000 -> "1000"). That breaks the fixed-width encoding and can lead to collisions or decode errors downstream. Consider not generating numeric IDs for out-of-range widgets (e.g., fallback to item-name IDs when possible, otherwise fail fast) so the system degrades cleanly beyond the supported limit.
| // Build the id by concatenating the child index at each level from top (main page) to bottom (sub-page), | ||
| // using WIDGET_ID_CODING_SIZE (3) digits at each level. | ||
| // This coding allows until MAX_SUPPORTED_CHILDREN (1000) items at each level. | ||
| String id = ""; |
There was a problem hiding this comment.
getWidgetId’s updated 3-digit encoding changes the externally visible widgetId format (used by REST /sitemaps and /proxy). The ItemUIRegistry interface JavaDoc still describes the old 2-digit encoding (example "0503"), which is now misleading. Please update the public API docs accordingly so clients understand the new format/limits.
| public String getWidgetId(Widget widget) { | ||
| Widget w2 = defaultWidgets.get(widget); | ||
| if (w2 != null) { | ||
| return getWidgetId(w2); | ||
| } | ||
|
|
||
| // Build the id by concatenating the child index at each level from top (main page) to bottom (sub-page), | ||
| // using WIDGET_ID_CODING_SIZE (3) digits at each level. | ||
| // This coding allows until MAX_SUPPORTED_CHILDREN (1000) items at each level. | ||
| String id = ""; | ||
| Widget w = widget; | ||
| boolean error = false; | ||
| while (w.getParent() instanceof LinkableWidget parent) { | ||
| String index = String.valueOf(parent.getWidgets().indexOf(w)); | ||
| if (index.length() == 1) { | ||
| index = "0" + index; // make it two digits | ||
| } | ||
| int num = parent.getWidgets().indexOf(w); | ||
| error |= (num >= MAX_SUPPORTED_CHILDREN); | ||
| String index = String.format(WIDGET_ID_CODING_FORMAT, num); | ||
| id = index + id; | ||
| w = parent; | ||
| } | ||
| if (w.getParent() instanceof Sitemap sitemap) { | ||
| String index = String.valueOf(sitemap.getWidgets().indexOf(w)); | ||
| if (index.length() == 1) { | ||
| index = "0" + index; // make it two digits | ||
| } | ||
| int num = sitemap.getWidgets().indexOf(w); | ||
| error |= (num >= MAX_SUPPORTED_CHILDREN); | ||
| String index = String.format(WIDGET_ID_CODING_FORMAT, num); | ||
| id = index + id; | ||
| } | ||
| if (error) { | ||
| logger.error( | ||
| "You have too many sub-widgets at a certain level of your sitemap; openHAB only supports a maximum of {}", | ||
| MAX_SUPPORTED_CHILDREN); | ||
| } |
There was a problem hiding this comment.
This PR changes widgetId encoding/decoding logic, but there are no unit tests covering (a) 3-digit roundtrip getWidgetId -> getWidget, (b) backward compatibility with the previous 2-digit IDs (if intended), and (c) behavior for malformed/negative IDs and the 999/1000 boundary. Adding focused tests in ItemUIRegistryImplTest would help prevent regressions for REST/proxy consumers.
|
Even if it was not my choice as I wanted to keep that as simple as possible considering that this probably impacts only very users all over the world, it is of course possible to implement something more complex in the coding of these ID so that old ID coding are still supported. |
The previous limit was 100.
An error will also be logged in case of detection of more than 1000 widgets in a sitemap frame/page when the page is opened.
Closes #5434