Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow ProfileTypeBuilder to pass its three filters list to both implementations of ProfileType #4325

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
import org.openhab.core.thing.dto.ChannelTypeDTO;
import org.openhab.core.thing.profiles.ProfileType;
import org.openhab.core.thing.profiles.ProfileTypeRegistry;
import org.openhab.core.thing.profiles.TriggerProfileType;
import org.openhab.core.thing.type.ChannelKind;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry;
Expand Down Expand Up @@ -174,10 +173,8 @@ public Response getLinkableItemTypes(

Set<String> result = new HashSet<>();
for (ProfileType profileType : profileTypeRegistry.getProfileTypes()) {
if (profileType instanceof TriggerProfileType type) {
if (type.getSupportedChannelTypeUIDs().contains(ctUID)) {
result.addAll(profileType.getSupportedItemTypes());
}
if (profileType.getSupportedChannelTypeUIDs().contains(ctUID)) {
result.addAll(profileType.getSupportedItemTypes());
}
}
if (result.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,10 @@ public Response link(@PathParam("itemName") @Parameter(description = "itemName")
}
if (!(profileType.getSupportedItemTypes().isEmpty()
|| profileType.getSupportedItemTypes().contains(itemType))
|| !(((TriggerProfileType) profileType).getSupportedChannelTypeUIDs().isEmpty()
|| ((TriggerProfileType) profileType).getSupportedChannelTypeUIDs()
.contains(channel.getChannelTypeUID()))) {
|| !(profileType.getSupportedChannelTypeUIDs().isEmpty()
|| profileType.getSupportedChannelTypeUIDs().contains(channel.getChannelTypeUID()))
|| !(profileType.getSupportedItemTypesOfChannel().isEmpty()
|| profileType.getSupportedItemTypesOfChannel().contains(itemType))) {
Copy link
Member

Choose a reason for hiding this comment

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

That looks really horrible. It would probably be better to

   Collection<String> supportedItemTypes = profileType.getSupportedItemTypes();
   ...
   if ((!supportedItemType.isEmpty() && !supportedItemTypes.contains(itemType)) || ...) {

Why do you check profileType.getSupportedItemTypesOfChannel? A profile can change the item-type:

  • The timestamp update profile works with all channel-types (e.g. a humidity channel with supported item-type Number:Dimensionless) but can only be linked to DateTime items. So a check would fail (in fact, currently the profile does not provide information about accepted channel types, so this will not cause an issue, but in principle it could).
  • A profile could map numeric values to strings, so the channel would support Number, but the profile String. In this case you could never link them.

Copy link
Author

Choose a reason for hiding this comment

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

I agree that it looks horrible, but it was jut to "fit in" with the already existing code.

As to why I do the check, well it's because I did a global search for the interface methods and made sure both methods are called in all the places where one was called following an instanceof call.

Copy link
Member

Choose a reason for hiding this comment

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

I agree, the style was not good before either and if you want to keep it: ok. But the getSupportedItemTypesOfChannel is excluding valid combinations.

Copy link
Author

Choose a reason for hiding this comment

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

I'm definitely in favor of changing the code style here, but as always when I'm submitting a pull request, I try to limit my changes to the code logic, adapting to the local style I encounter.
I'll try to come up with a more sensible way of writing this up.

// item or channel type not matching
return Response.status(Status.BAD_REQUEST).build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
import org.openhab.core.items.ItemUtil;
import org.openhab.core.thing.profiles.ProfileType;
import org.openhab.core.thing.profiles.ProfileTypeRegistry;
import org.openhab.core.thing.profiles.StateProfileType;
import org.openhab.core.thing.profiles.TriggerProfileType;
import org.openhab.core.thing.profiles.dto.ProfileTypeDTO;
import org.openhab.core.thing.profiles.dto.ProfileTypeDTOMapper;
import org.openhab.core.thing.type.ChannelType;
Expand Down Expand Up @@ -128,13 +126,7 @@ private Predicate<ProfileType> matchesChannelUID(@Nullable String channelTypeUID
// requested to filter against an unknown channel type -> do not return a ProfileType
return t -> false;
}
switch (channelType.getKind()) {
case STATE:
return t -> stateProfileMatchesProfileType(t, channelType);
case TRIGGER:
return t -> triggerProfileMatchesProfileType(t, channelType);
}
return t -> false;
return t -> profileTypeMatchesChannelType(t, channelType);
J-N-K marked this conversation as resolved.
Show resolved Hide resolved
}

private Predicate<ProfileType> matchesItemType(@Nullable String itemType) {
Expand All @@ -151,31 +143,19 @@ private boolean profileTypeMatchesItemType(ProfileType pt, String itemType) {
|| supportedItemTypesOnProfileType.contains(itemType);
}

private boolean triggerProfileMatchesProfileType(ProfileType profileType, ChannelType channelType) {
if (profileType instanceof TriggerProfileType triggerProfileType) {
if (triggerProfileType.getSupportedChannelTypeUIDs().isEmpty()) {
return true;
}

if (triggerProfileType.getSupportedChannelTypeUIDs().contains(channelType.getUID())) {
return true;
}
private boolean profileTypeMatchesChannelType(ProfileType profileType, ChannelType channelType) {
if (profileType.getSupportedChannelTypeUIDs().isEmpty()
&& profileType.getSupportedItemTypesOfChannel().isEmpty()) {
return true;
}
return false;
}

private boolean stateProfileMatchesProfileType(ProfileType profileType, ChannelType channelType) {
if (profileType instanceof StateProfileType stateProfileType) {
if (stateProfileType.getSupportedItemTypesOfChannel().isEmpty()) {
return true;
}

Collection<String> supportedItemTypesOfChannelOnProfileType = stateProfileType
.getSupportedItemTypesOfChannel();
String itemType = channelType.getItemType();
return itemType != null
&& supportedItemTypesOfChannelOnProfileType.contains(ItemUtil.getMainItemType(itemType));
if (profileType.getSupportedChannelTypeUIDs().contains(channelType.getUID())) {
return true;
}
return false;

Collection<String> supportedItemTypesOfChannelOnProfileType = profileType.getSupportedItemTypesOfChannel();
String itemType = channelType.getItemType();
return itemType != null
&& supportedItemTypesOfChannelOnProfileType.contains(ItemUtil.getMainItemType(itemType));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.openhab.core.config.core.ParameterOption;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.ItemUtil;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingRegistry;
Expand All @@ -38,6 +39,8 @@
import org.openhab.core.thing.profiles.ProfileTypeRegistry;
import org.openhab.core.thing.profiles.StateProfileType;
import org.openhab.core.thing.profiles.TriggerProfileType;
import org.openhab.core.thing.type.ChannelType;
import org.openhab.core.thing.type.ChannelTypeRegistry;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
Expand All @@ -55,16 +58,19 @@ public class ItemChannelLinkConfigDescriptionProvider implements ConfigDescripti
public static final String PARAM_PROFILE = "profile";

private final ProfileTypeRegistry profileTypeRegistry;
private final ChannelTypeRegistry channelTypeRegistry;
private final ItemChannelLinkRegistry itemChannelLinkRegistry;
private final ItemRegistry itemRegistry;
private final ThingRegistry thingRegistry;

@Activate
public ItemChannelLinkConfigDescriptionProvider(final @Reference ProfileTypeRegistry profileTypeRegistry, //
final @Reference ChannelTypeRegistry channelTypeRegistry, //
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, //
final @Reference ItemRegistry itemRegistry, //
final @Reference ThingRegistry thingRegistry) {
this.profileTypeRegistry = profileTypeRegistry;
this.channelTypeRegistry = channelTypeRegistry;
this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.itemRegistry = itemRegistry;
this.thingRegistry = thingRegistry;
Expand Down Expand Up @@ -108,10 +114,11 @@ private List<ParameterOption> getOptions(ItemChannelLink link, Item item, Channe
return profileTypes.stream().filter(profileType -> {
switch (channel.getKind()) {
case STATE:
return profileType instanceof StateProfileType && isSupportedItemType(profileType, item);
return profileType instanceof StateProfileType && isSupportedItemType(profileType, item)
&& isSupportedChannelType(profileType, channel, locale);
case TRIGGER:
return profileType instanceof TriggerProfileType tpt && isSupportedItemType(profileType, item)
&& isSupportedChannelType(tpt, channel);
return profileType instanceof TriggerProfileType && isSupportedItemType(profileType, item)
&& isSupportedChannelType(profileType, channel, locale);
default:
throw new IllegalArgumentException("Unknown channel kind: " + channel.getKind());
}
Expand All @@ -123,8 +130,25 @@ private boolean isSupportedItemType(ProfileType profileType, Item item) {
|| profileType.getSupportedItemTypes().contains(item.getType());
}

private boolean isSupportedChannelType(TriggerProfileType profileType, Channel channel) {
return profileType.getSupportedChannelTypeUIDs().isEmpty()
|| profileType.getSupportedChannelTypeUIDs().contains(channel.getChannelTypeUID());
private boolean isSupportedChannelType(ProfileType profileType, Channel channel, @Nullable Locale locale) {
if (profileType.getSupportedChannelTypeUIDs().isEmpty()
&& profileType.getSupportedItemTypesOfChannel().isEmpty()) {
return true;
}

ChannelType channelType = channelTypeRegistry.getChannelType(channel.getChannelTypeUID(), locale);
if (channelType == null) {
// requested to filter against an unknown channel type
return false;
J-N-K marked this conversation as resolved.
Show resolved Hide resolved
}

if (profileType.getSupportedChannelTypeUIDs().contains(channelType.getUID())) {
return true;
}

Collection<String> supportedItemTypesOfChannelOnProfileType = profileType.getSupportedItemTypesOfChannel();
String itemType = channelType.getItemType();
return itemType != null
&& supportedItemTypesOfChannelOnProfileType.contains(ItemUtil.getMainItemType(itemType));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.profiles.ProfileTypeUID;
import org.openhab.core.thing.profiles.StateProfileType;
import org.openhab.core.thing.type.ChannelTypeUID;

/**
* Default implementation of a {@link StateProfileType}.
Expand All @@ -31,20 +32,27 @@ public class StateProfileTypeImpl implements StateProfileType {
private final String label;
private final Collection<String> supportedItemTypes;
private final Collection<String> supportedItemTypesOfChannel;
private final Collection<ChannelTypeUID> supportedChannelTypeUIDs;

public StateProfileTypeImpl(ProfileTypeUID profileTypeUID, String label, Collection<String> supportedItemTypes,
Collection<String> supportedItemTypesOfChannel) {
Collection<String> supportedItemTypesOfChannel, Collection<ChannelTypeUID> supportedChannelTypeUIDs) {
this.profileTypeUID = profileTypeUID;
this.label = label;
this.supportedItemTypes = Collections.unmodifiableCollection(supportedItemTypes);
this.supportedItemTypesOfChannel = Collections.unmodifiableCollection(supportedItemTypesOfChannel);
this.supportedChannelTypeUIDs = Collections.unmodifiableCollection(supportedChannelTypeUIDs);
}

@Override
public ProfileTypeUID getUID() {
return profileTypeUID;
}

@Override
public Collection<ChannelTypeUID> getSupportedChannelTypeUIDs() {
return supportedChannelTypeUIDs;
}

@Override
public Collection<String> getSupportedItemTypes() {
return supportedItemTypes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ public class TriggerProfileTypeImpl implements TriggerProfileType {
private final ProfileTypeUID profileTypeUID;
private final String label;
private final Collection<String> supportedItemTypes;
private final Collection<String> supportedItemTypesOfChannel;
private final Collection<ChannelTypeUID> supportedChannelTypeUIDs;

public TriggerProfileTypeImpl(ProfileTypeUID profileTypeUID, String label, Collection<String> supportedItemTypes,
Collection<ChannelTypeUID> supportedChannelTypeUIDs) {
Collection<String> supportedItemTypesOfChannel, Collection<ChannelTypeUID> supportedChannelTypeUIDs) {
this.profileTypeUID = profileTypeUID;
this.label = label;
this.supportedItemTypes = Collections.unmodifiableCollection(supportedItemTypes);
this.supportedItemTypesOfChannel = Collections.unmodifiableCollection(supportedItemTypesOfChannel);
this.supportedChannelTypeUIDs = Collections.unmodifiableCollection(supportedChannelTypeUIDs);
}

Expand All @@ -60,4 +62,9 @@ public String getLabel() {
public ProfileTypeUID getUID() {
return profileTypeUID;
}

@Override
public Collection<String> getSupportedItemTypesOfChannel() {
return supportedItemTypesOfChannel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.common.registry.Identifiable;
import org.openhab.core.thing.type.ChannelTypeUID;

/**
* Describes a profile type.
Expand All @@ -31,6 +32,19 @@ public interface ProfileType extends Identifiable<ProfileTypeUID> {
*/
Collection<String> getSupportedItemTypes();

/**
* Get a collection of ItemType names that a Channel needs to support in order to able to use this ProfileType
*
* @return a collection of supported ItemType names (an empty list means ALL types are supported)
*/
Collection<String> getSupportedItemTypesOfChannel();

/**
*
J-N-K marked this conversation as resolved.
Show resolved Hide resolved
* @return a collection of ChannelTypeUIDs (may be empty if all are supported).
*/
Collection<ChannelTypeUID> getSupportedChannelTypeUIDs();

/**
* Get a human readable description.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static ProfileTypeBuilder<StateProfileType> newState(ProfileTypeUID profi
return new ProfileTypeBuilder<>(profileTypeUID, label,
(leProfileTypeUID, leLabel, leSupportedItemTypes, leSupportedItemTypesOfChannel,
leSupportedChannelTypeUIDs) -> new StateProfileTypeImpl(leProfileTypeUID, leLabel,
leSupportedItemTypes, leSupportedItemTypesOfChannel));
leSupportedItemTypes, leSupportedItemTypesOfChannel, leSupportedChannelTypeUIDs));
}

/**
Expand All @@ -78,7 +78,7 @@ public static ProfileTypeBuilder<TriggerProfileType> newTrigger(ProfileTypeUID p
return new ProfileTypeBuilder<>(profileTypeUID, label,
(leProfileTypeUID, leLabel, leSupportedItemTypes, leSupportedItemTypesOfChannel,
leSupportedChannelTypeUIDs) -> new TriggerProfileTypeImpl(leProfileTypeUID, leLabel,
leSupportedItemTypes, leSupportedChannelTypeUIDs));
leSupportedItemTypes, leSupportedItemTypesOfChannel, leSupportedChannelTypeUIDs));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
*/
package org.openhab.core.thing.profiles;

import java.util.Collection;

import org.eclipse.jdt.annotation.NonNullByDefault;

/**
Expand All @@ -24,11 +22,4 @@
*/
@NonNullByDefault
public interface StateProfileType extends ProfileType {

/**
* Get a collection of ItemType names that a Channel needs to support in order to able to use this ProfileType
*
* @return a collection of supported ItemType names (an empty list means ALL types are supported)
*/
Collection<String> getSupportedItemTypesOfChannel();
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
*/
package org.openhab.core.thing.profiles;

import java.util.Collection;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.type.ChannelTypeUID;

/**
* Describes a {@link TriggerProfile} type.
Expand All @@ -24,10 +21,4 @@
*/
@NonNullByDefault
public interface TriggerProfileType extends ProfileType {

/**
*
* @return a collection of ChannelTypeUIDs (may be empty if all are supported).
*/
Collection<ChannelTypeUID> getSupportedChannelTypeUIDs();
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ public ProfileType createLocalizedProfileType(Bundle bundle, ProfileType profile
if (profileType instanceof StateProfileType type) {
return ProfileTypeBuilder.newState(profileTypeUID, label != null ? label : defaultLabel)
.withSupportedItemTypes(profileType.getSupportedItemTypes())
.withSupportedItemTypesOfChannel(type.getSupportedItemTypesOfChannel()).build();
.withSupportedItemTypesOfChannel(type.getSupportedItemTypesOfChannel())
.withSupportedChannelTypeUIDs(type.getSupportedChannelTypeUIDs()).build();
} else if (profileType instanceof TriggerProfileType type) {
return ProfileTypeBuilder.newTrigger(profileTypeUID, label != null ? label : defaultLabel)
.withSupportedItemTypes(profileType.getSupportedItemTypes())
.withSupportedItemTypesOfChannel(type.getSupportedItemTypesOfChannel())
.withSupportedChannelTypeUIDs(type.getSupportedChannelTypeUIDs()).build();
} else {
return profileType;
Expand Down
Loading