Skip to content

Conversation

@mherwege
Copy link
Contributor

@mherwege mherwege commented Sep 3, 2025

With this PR, a central sitemap registry is created. This registry has providers that offer sitemaps provide sitemaps from different providers. The current ones are DSL sitemaps and UI created sitemaps. The code for these has been refactored to implement such providers.

The reasons for doing this are:

  • Currently the UI created sitemaps are created as model sitemaps in core, residing in the org.openhab.core.model.sitemap, so org.openhab.core.ui depends on this model package.
  • Without a registry which is decoupled from the model, that same model depency would have to be included in a YAML sitemap provider.
  • With the current structure, it is impossible to show the file based sitemaps in the UI, as they are not converted to a common format. It is one way. The same would be true for converting these to YAML. It would have to be based on the sitemap representation in the model classes.

With the current structure, whatever we do when creating a new sitemap provider forces pulling the org.openhab.core.model.sitemap package directly or indirectly.
It therefore seems more appropriate to decouple the internal sitemap representation from the DSL model and xtext code generation.

See for the background: #4945 (comment) and #4945 (comment)

This PR prepares for:

  • Create a YAML sitemap provider.
  • Supporting a YAML format for sitemaps with the possibility to convert between them. See Sitemap DSL and YAML serialization #4945. This linked PR should be refactored to build on this one.
  • Refactor UI code to show (non-editable) representations of sitemaps provided from sitemap files or YAML files. This will require extra endpoints independent of the current once that only include configurations for UI managed sitemaps.
  • Do transparent conversions between the formats.

This PR is accompanied by the webui PR (openhab/openhab-webui#3349) that adapts the dependencies for BasicUI and CometVisu. Other UI's should not be concerned as they all work purely through the REST API and SSE events.

This is of course a major refactoring. Therefore there is a high risk and probability of some regressions and needs to be tested extensively. Code tests run through and my tests have not revealed issues so far. But I do expect there may be some.

@lolodomo I believe this is a better basis to continue work on YAML and DSL conversion afterwards.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements a core sitemap registry that decouples sitemap handling from the model packages. It creates a central registry for sitemaps with providers for different sources (DSL sitemaps and UI-created sitemaps) and introduces a new org.openhab.core.sitemap module with a factory-based approach for sitemap creation.

  • Creates a central SitemapRegistry to manage sitemaps from different providers
  • Introduces a new org.openhab.core.sitemap module with interfaces and implementations
  • Refactors existing UI sitemap provider to use the new registry architecture

Reviewed Changes

Copilot reviewed 91 out of 91 changed files in this pull request and generated 8 comments.

File Description
Feature/Karaf configurations Updates feature definitions to include new sitemap module and remove model dependencies
Test configurations Adds sitemap module dependency to integration test bundles
UI module refactoring Updates UI components to use new sitemap interfaces instead of model classes
New sitemap module Introduces core sitemap interfaces, registry, factory, and implementations

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines 260 to 261
try {
uri = createURIFromString(uriString);
uri = createURIFromString(uriString != null ? uriString : "");
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing an empty string to createURIFromString when uriString is null may cause MalformedURLException or URISyntaxException. The original null check and early return should be preserved or handled appropriately.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change that. The problem was there before but would generate a null pointer exception, as the model classes are not annotated.


private static final Pattern CONDITION_PATTERN = Pattern
.compile("((?<item>[A-Za-z]\\w*)?\\s*(?<condition>==|!=|<=|>=|<|>))?\\s*(?<sign>\\+|-)?(?<state>.+)");
.compile("((?<item>[A-Za-z]\\w*)?\\s*(?<condition>==|!=|<=|>=|<|>))?\\s*(?<value>(\\+|-)?.+)");
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern change from separate 'sign' and 'state' groups to a single 'value' group may break existing condition parsing. The original pattern allowed for more structured parsing of conditions.

Suggested change
.compile("((?<item>[A-Za-z]\\w*)?\\s*(?<condition>==|!=|<=|>=|<|>))?\\s*(?<value>(\\+|-)?.+)");
.compile("((?<item>[A-Za-z]\\w*)?\\s*(?<condition>==|!=|<=|>=|<|>))?\\s*(?<sign>\\+|-)?(?<state>.+)");

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The separate sign read into a separate field was only there to cope with a DSL parser limitation. The full value is needed, so no need to replicate these separate fields in the core representation of a condition value.

Comment on lines 302 to 304
mapping.setCmd(cmd != null ? cmd : "");
mapping.setReleaseCmd(releaseCmd);
mapping.setLabel(label);
mapping.setLabel(label != null ? label : "");
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting empty strings as default values for cmd and label may cause issues if the consuming code expects null values for missing/unset commands and labels.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fine.

Comment on lines 302 to 304
mapping.setCmd(cmd != null ? cmd : "");
mapping.setReleaseCmd(releaseCmd);
mapping.setLabel(label);
mapping.setLabel(label != null ? label : "");
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting empty strings as default values for cmd and label may cause issues if the consuming code expects null values for missing/unset commands and labels.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fine.

if (sourceRules instanceof Collection<?> sourceRulesCollection) {
for (Object sourceRule : sourceRulesCollection) {
if (sourceRule instanceof String) {
String argument = !key.equals("visibility") ? getRuleArgument(sourceRule.toString()) : null;
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The hardcoded string comparison with 'visibility' makes the code brittle. Consider using constants or an enum for rule types to improve maintainability.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt it is worth externalizing just this string.

import org.osgi.service.component.annotations.Component;

/**
* The {@link SitemapFactoryImpl} implements the {@link SitemapRegistry}
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class comment incorrectly states that SitemapFactoryImpl implements SitemapRegistry, but it actually implements SitemapFactory.

Suggested change
* The {@link SitemapFactoryImpl} implements the {@link SitemapRegistry}
* The {@link SitemapFactoryImpl} implements the {@link SitemapFactory}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.


@Override
public String getWidgetType() {
return this.getClass().getInterfaces()[0].getSimpleName();
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing the first interface without checking if any interfaces exist can cause ArrayIndexOutOfBoundsException. This implementation assumes the widget always implements exactly one interface in a specific order.

Suggested change
return this.getClass().getInterfaces()[0].getSimpleName();
Class<?>[] interfaces = this.getClass().getInterfaces();
if (interfaces.length > 0) {
return interfaces[0].getSimpleName();
} else {
return this.getClass().getSimpleName();
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does assume it always implements the widget's interface and it is the first interface. I don't think these checks add much.

*
* @param visibility
*/
void setVisibility(List<Rule> visibility);
Copy link

Copilot AI Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter name 'visiblity' should be 'visibility' to match the method name and consistent naming convention.

Suggested change
void setVisibility(List<Rule> visibility);
void setVisibility(List<Rule> visibility);

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already changed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter name could be visibilityRules

@mherwege
Copy link
Contributor Author

mherwege commented Sep 4, 2025

There is a new package org.openhab.core.sitemap that has this sitemap registry code. org.openhab.core.ui still contains code that is only used for sitemaps (ItemUIRegistry, ChartProvider, ...). Should these be moved to this new package as well? Only UIComponentSitemapProvider would be left as long as managed sitemaps are stored in the UI component store.

Signed-off-by: Mark Herwege <[email protected]>
Signed-off-by: Mark Herwege <[email protected]>
Signed-off-by: Mark Herwege <[email protected]>
Signed-off-by: Mark Herwege <[email protected]>
@lolodomo
Copy link
Contributor

@mherwege : this message just to inform you that I am not ignoring your PR at all, I will review it.

List<ButtonDefinition> getButtons();

/**
* Replace the button grid buttons a new list of buttons.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "with" is missing

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

*
* @return label color rules
*/
List<Rule> getLabelColor();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rather getLabelColorRules and setLabelColorRules ?

Copy link
Contributor Author

@mherwege mherwege Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that would be possible. But it would also mean the change in consuming classes is more then just changing the import. As much as possible, I kept the same method names from what they where before in the model, so I only had to change imports and do some cleanup. But now may be the right time to use more appropriate names as this is a major change anyway. @lolodomo What do you think? I left it as is for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except if I miss something, that looks very easy to change and with no particular difficulty in both sitemap providers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not about the sitemap providers. It is about the UI's, where this change would have to be applied as well.

*
* @return value color rules
*/
List<Rule> getValueColor();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rather getValueColorRules and setValueColorRules ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

*
* @return icon color rules
*/
List<Rule> getIconColor();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rather getIconColorRules and setIconColorRules ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

*
* @return visibility rules
*/
List<Rule> getVisibility();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rather getVisibilityRules and setVisibilityRules ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above

* Returns the sitemap name.
*
* @return sitemap name.
* @see #setName(String)
Copy link
Contributor

@lolodomo lolodomo Sep 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these @see in this interface looks like useless as they just reference them each other.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended there because they started as copies of the generated model classes, but will remove.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

Comment on lines 39 to 42
private List<Rule> labelColor = new CopyOnWriteArrayList<>();
private List<Rule> valueColor = new CopyOnWriteArrayList<>();
private List<Rule> iconColor = new CopyOnWriteArrayList<>();
private List<Rule> visibility = new CopyOnWriteArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest labelColorRules, valueColorRules, ... etc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved


@Override
protected void notifyListenersAboutUpdatedElement(Sitemap oldElement, Sitemap element) {
registryChangeListeners.forEach(listener -> listener.updated(oldElement, element));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no notify method to call in super class ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be much more simple. As I ended up extending AbstractRegistry, only the last 2 methods (addSitemapProver and removeSitemapProvider) are needed. AbstractRegistry keeps track of the listeners itself. I will make the change that way, but will need to do a full test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

@lolodomo
Copy link
Contributor

I started by reviewing org.openhab.core.sitemap. The only question I have is if you did not forget that it is a possible to have a default rule condition to set a particular value when none of the other conditions are valid.
Regarding the default value of some attributes, I have not checked that the default is the same as before.

case Default defaultWidget:
setWidgetPropertyFromComponentConfig(defaultWidget, component, "height");
break;
default:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you forgot the case of Switch to call addWidgetMappings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, thank you.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

Comment on lines 302 to 304
mapping.setCmd(cmd != null ? cmd : "");
mapping.setReleaseCmd(releaseCmd);
mapping.setLabel(label);
mapping.setLabel(label != null ? label : "");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, you could do the same as in addWidgetButtons, that is testing if value is not null before calling setCmd and setLabel.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

@Test
public void getWidgetUnknownPageId() throws ItemNotFoundException {
Sitemap sitemap = SitemapFactory.eINSTANCE.createSitemap();
Sitemap sitemap = sitemapFactoryMock.createSitemap(SITEMAP_NAME);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it normal to not have any when(sitemapFactoryMock.createSitemap) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand your question here. I can't create a sitemap for testing anymore the same way as before when it was using the model. So I reverted to a mock.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As sitemapFactoryMock is a mock, I don't understand what can be the result of calling sitemapFactoryMock.createSitemap if you don't define something like when(sitemapFactoryMock.createSitemap)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, looks like sitemap wasn't on the execution path, but I adjusted it anyway.

if (itemToBeSent != null) {
String widgetTypeName = widget.eClass().getInstanceTypeName()
.substring(widget.eClass().getInstanceTypeName().lastIndexOf(".") + 1);
String widgetTypeName = widget.getClass().getSimpleName();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather widget.getWidgetType() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this when creating the method in Widget.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

@mherwege
Copy link
Contributor Author

The only question I have is if you did not forget that it is a possible to have a default rule condition to set a particular value when none of the other conditions are valid.

The behaviour should not have changed. item and condition in a Condition are nullable, only value is not.

Signed-off-by: Mark Herwege <[email protected]>
Signed-off-by: Mark Herwege <[email protected]>
@Override
public @Nullable String getConditionalIcon(Widget w) {
List<IconRule> ruleList = w.getIconRules();
List<Rule> rulList = w.getIconRules();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix typo => ruleList

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

protected @Nullable Widget buildWidget(UIComponent component, Parent parent) {
Widget widget = sitemapFactory.createWidget(component.getType(), parent);

if (widget != null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could keep the existing warning "Unknown sitemap component type" in case widget is null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

Class<?> clazz = widget.getClass();
Method method = List.of(clazz.getMethods()).stream().filter(m -> m.getName().equals(setterName)).findFirst()
.get();
Class<?> argumentType = (method.getParameters()[0].getType());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove unnecessary parenthesis

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

Rule rule = sitemapFactory.createRule();
List<Condition> conditions = getConditions(conditionsString, component, key);
rule.setConditions(conditions);
rules.add(rule);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you forgot to call rule.setArgument when key is not "visibility".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.

('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);

ButtonDefinition:
ModelFrame:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the need to prefix everything with "Model" ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new registry now has all of these classes without Model in front. If I would have kept the class names here, I would have ended up having to fully qualify in the methods I need both. I wanted to avoid that to keep the code cleaner and have a clear distinction. It will also avoid errors in external code as it should be clear the registry classes should be used rather than the model classes (it will not compile when it is not changed).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes I understand your point now.
Resolved.

Comment on lines +27 to +32
{ModelFrame} 'Frame' (('item=' item=ItemRef) | ('label=' label=(ID | STRING)) |
('icon=' icon=Icon) | ('icon=' IconRules=ModelIconRuleList) | ('staticIcon=' staticIcon=Icon) |
('labelcolor=' labelColor=ModelColorArrayList) |
('valuecolor=' valueColor=ModelColorArrayList) |
('iconcolor=' iconColor=ModelColorArrayList) |
('visibility=' visibility=ModelVisibilityRuleList))*;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you replace many "&" by "|" ?

Copy link
Contributor Author

@mherwege mherwege Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The & operator used like before leads to a Too Many Class Methods error. The issue is that xtext will create Java methods for each possible permutation in all possible sequences. This number of methods becomes huge very quickly. As I introduced the various List classes for the rules, I ran into the limit of > 65535 methods on the generated Java class. Adding syntactical elements at any point in time would probably have gotten us at the limit as well.

That's also the reason why I added extra checks for item and icon in the validator, as this is no longer enforced by the syntax.

The alternative approach would have been to fix the sequence of the attributes in the grammar, but that would have been a breaking change in the syntax.

Comment on lines +331 to +332
Rule colorRule = sitemapFactory.createRule();
addRuleConditions(colorRule.getConditions(), modelColorRule.getConditions());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to colorRule.setArgument is missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

Comment on lines +399 to +403
case EventType.MODIFIED:
if (sitemap != null && oldSitemap != null) {
notifyListenersAboutUpdatedElement(oldSitemap, sitemap);
}
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know if you have to consider the case where oldSitemap is null and then calling notifyListenersAboutAddedElement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I could see, ADDED is being called (and should be called) when oldSitemap is null. The check in the MODIFIED case is just there to satisfy null annotations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.
Resolved

Comment on lines +415 to +417
getAll().forEach(sitemap -> {
notifyListenersAboutAddedElement(sitemap);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure that it is necessary ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't that be needed if the sitemap model bundle gets started after the sitemap registry bundle? I need to check, put a breakpoint in this method to see if it gets called. But it may be difficult as testing in Eclipse may have a different sequence than in real live.
In the worst case, it is never called. Does it harm?

Comment on lines 209 to 208
boolean itemBelongsToWidget = w.getItem() != null && w.getItem().equals(item.getName());
boolean itemBelongsToWidget = w.getItem() != null && item.getName().equals(w.getItem());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you reverse the equals ?
At least we are sure that w.getItem() is not null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item.getName() is now correctly annotated as NonNull in the registry. Eclipse still gives me a warning for w.getItem() potentially null if you put it first. In theory, it could be, as you call w.getItem() twice and you should assign it to a local variable instead to avoid this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could actually drop the w.getItem() != null check completely now.

if (!skipWidget && w instanceof Chart chartWidget) {
skipWidget = chartWidget.getRefresh() > 0;
Integer refresh = chartWidget.getRefresh();
skipWidget = refresh != null && refresh > 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chartWidget.getRefresh() returns an int so previous code was good and there is nothing to change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, indeed. I alternated between making it an Integer or not when developing I believe, but sticked with int in the end.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

// event.item contains the (potentially changed) data of the item belonging to
// the widget including its state (in event.item.state)
boolean itemBelongsToWidget = widget.getItem() != null && widget.getItem().equals(item.getName());
boolean itemBelongsToWidget = widget.getItem() != null && item.getName().equals(widget.getItem());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, inverting avoid a null pointer warning in Eclipse.

Comment on lines -617 to +594
bean.staticIcon = widget.getStaticIcon() != null || !widget.getIconRules().isEmpty();
bean.staticIcon = widget.isStaticIcon() || !widget.getIconRules().isEmpty();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bean.staticIcon = (widget.getIcon() != null && widget.isStaticIcon()) || !widget.getIconRules().isEmpty();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is necessary.

@lolodomo
Copy link
Contributor

I just finished a full review.

@lolodomo
Copy link
Contributor

lolodomo commented Dec 1, 2025

I am asking myself about the risk to merge that change for 5.1, considering there is not a lot of time before the release. Maybe better to do it just after 5.1 is released?
I also started to review the required UI PR.

@mherwege
Copy link
Contributor Author

mherwege commented Dec 1, 2025

I am asking myself about the risk to merge that change for 5.1, considering there is not a lot of time before the release. Maybe better to do it just after 5.1 is released?
I also started to review the required UI PR.

I was asking myself the same thing, and I agree. I also think that would give me the time to pick up working on the YAML side again and make it all available in OH5.2.

Signed-off-by: Mark Herwege <[email protected]>
@mherwege
Copy link
Contributor Author

mherwege commented Dec 1, 2025

@lolodomo Thank you very much for your extensive review. I made review adjustments and left a few comments.
I notice there are a few conflicts, but I will refrain from rebasing until we are through the review.

@lolodomo
Copy link
Contributor

lolodomo commented Dec 1, 2025

I realise that one file (sitemap validation checks) remains to be reviewed.

Signed-off-by: Mark Herwege <[email protected]>
@mherwege
Copy link
Contributor Author

mherwege commented Jan 5, 2026

@lolodomo Should I rebase this now we are working towards OH 5.2, or do you want me to wait? How do you want to proceed?
I very much won't to not let this to the last moment before a release. This is too risky.

@lolodomo
Copy link
Contributor

lolodomo commented Jan 5, 2026

Let me finish the review first, it was done at around 98% (just one file still to be reviewed), I also need to check your last changes.
Then I will have to review your corresponding UI PR (already started) as they will have to be merged together.
Your stuff is my review priority 2, the first being YAML rule file provider by @Nadahar (who is waiting since more time than you).
My intention, even if I am not the one who can decide & merge, would be to have both YAML rule file provider and new sitemap core registry in first milestone of 5.2.
Then you can continue the work with sitemap (YAML, integration to create and parse APIs, changes in Main UI) during 5.2 development.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants