Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Profile API improvements #4516

Merged
merged 9 commits into from
Nov 10, 2017

Conversation

sjsf
Copy link
Contributor

@sjsf sjsf commented Nov 8, 2017

Having had some first feedback and some chats with @kaikreuzer, it obviously made sense to rework and simplify the profile API at some points. This is the current result.

  • Simplified the API for implementing profiles
    (at the price of a little more complexity on CommunicationManager side)
  • Allow implementing profiles without exposing Items and ItemChannelLinks
    to bindings
  • Restore backward-compatibility by making the default master profile
    forward handleUpdate() calls to ThingHandlers again (see also CommunicationManager & DefaultMasterProfile : linking items through channels not supported by default #4464 (comment))
  • Exposing constants in SystemProfiles
  • Allow for easier evolvement of the API
  • Having the ProfileCallbacks requires less code within profiles and therefore
    eliminates the need to export the default profiles for inheritance.
  • Renamed system profiles from master/slave to default/follow

Although this technically is APIBreaking (and therefore adding the corresponding label), there cannot yet exist a productive usage of this API, therefore I don't see any risks involved here.

Signed-off-by: Simon Kaufmann simon.kfm@googlemail.com

@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/enocean-bindings-opencean-or-aleoncean/12493/57

* Simplified the API for implementing profiles
  (at the price of a little more complexity on CommunicationManager side)
* Allow implementing profiles without exposing Items and ItemChannelLinks
  to bindings
* Maintain backward-compatibility by making the default master profile
  forward handleUpdate() calls to ThingHandlers again
* Exposing constants in SystemProfiles
* Allow for easier evolvement of the API
* Having the ProfileCallbacks requires less code within profiles and therefore
  eliminates the need to export the default profiles for inheritance.

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
}

public void removeProfileAdvisor(ProfileAdvisor profileAdvisor) {
profileAdvisors.remove(profileAdvisor);
public void removeProfileAdvisor(ProfileTypeRegistry profileTypeRegistry) {
Copy link
Contributor

@kungfoolfighting kungfoolfighting Nov 8, 2017

Choose a reason for hiding this comment

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

This function and the addProfileAdvisor function should probably be renamed, right?

public static final TriggerProfileType RAWBUTTON_TOGGLE_SWITCH_TYPE = new TriggerProfileType() {
@Override
public ProfileTypeUID getUID() {
return SLAVE;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wrong UID

}

private boolean isSupportedChannelType(ProfileType profileType, Channel channel) {
return profileType instanceof StateProfileType
Copy link
Contributor

Choose a reason for hiding this comment

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

profileType instanceof TriggerProfileType?

Copy link
Contributor

Choose a reason for hiding this comment

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

No I think that StateProfileType is what is meant here, but I don't quite understand why a StateProfileType would always support all ChannelTypes. Could there not be profiles that only support a specific channel type?

/**
* Constant for mathing *ANY* item type.
*/
public static final Collection<String> ANY_ITEM_TYPE = new ArrayList<>(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a minor notice:
We can declare variables in Java interfaces. By default, these are public, final and static.
So, no need to add the default modifiers.

* @author Simon Kaufmann - initial contribution and API.
*
*/
public interface SystemProfiles {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comments about default modifiers as above.

/**
* Constant for mathing *ANY* channel type.
*/
public static final Collection<ChannelTypeUID> ANY_CHANNEL_TYPE = new ArrayList<>(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

see above (default modifiers)


private boolean isSupportedChannelType(ProfileType profileType, Channel channel) {
return profileType instanceof StateProfileType
|| ((TriggerProfileType) profileType)
Copy link
Contributor

Choose a reason for hiding this comment

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

While it is currently the case that usually profiles fall within the StateProfileType or the TriggerProfileType group, it would make sense to check if the profile type is an instance of TriggerProfileType here anyways in order to make sure we dont get a problem here later, in case other types are added.

Simon Kaufmann added 2 commits November 9, 2017 13:46
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
@kungfoolfighting
Copy link
Contributor

I might have done something wrong, but a working item definition that used the rawbutton channel and a toggle profile stopped working after I merged this patch.
I get a log entry that says It was not able to find a profile factory for this profile type. This message is from line 211 in CommunicationManager.

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
@sjsf
Copy link
Contributor Author

sjsf commented Nov 9, 2017

Thanks, I will have a look.

@sjsf
Copy link
Contributor Author

sjsf commented Nov 9, 2017

What does your item definition look like?
And what exactly does the warning in your log say?

@@ -107,7 +107,7 @@ private boolean isSupportedItemType(ProfileType profileType, Item item) {
}

private boolean isSupportedChannelType(ProfileType profileType, Channel channel) {
return profileType instanceof StateProfileType
return profileType instanceof TriggerProfileType
Copy link
Contributor

Choose a reason for hiding this comment

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

This must be wrong now. It would now always return true if profileType is of type TriggerProfileType. That would mean that the rest of the condition is superfluous.

Simon Kaufmann added 3 commits November 9, 2017 13:59
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
...from master/slave to default/follow

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
@philomatic
Copy link
Contributor

Thanks for being compliant with me! 😄

If I get this right there is no need for another ProfileCallback implementation right now (Profiles alone "should" be enough for information flow)?
It's irritating in the first moment, but reduces complexity for new profiles and code duplication a lot!

LGTM!

@philomatic
Copy link
Contributor

philomatic commented Nov 9, 2017

How do you want to deal with

@Deprecated
void handleUpdate(ChannelUID channelUID, State newState);

in ThingManager?

I think we should either stay backward-compatible by forwarding handleUpdate() calls (and therefore cancel deprecation?) or drop support for handleUpdate() completely before 1.0.
Just mentioning this so we won't have to deal with it twice.

Best regards

@kungfoolfighting
Copy link
Contributor

kungfoolfighting commented Nov 9, 2017

@SJKA I don't have the code at work atm. But it looks something like this:
Switch ToggleSwitch {channel="bindingname:thingID:triggerChannelName" [profile="system:RawButtonToggleSwitchProfile"] }
Thinking about it, maybe I forgot to rename the profile from RawButtonToggleProfile to RawButtonToggleSwitchProfile. It was very late yesterday. So I will check tonight and keep you posted.

@sjsf
Copy link
Contributor Author

sjsf commented Nov 9, 2017

maybe I forgot to rename the profile

That's why I've been asking... It should read rawbutton-toggle-switch or system:rawbutton-toggle-switch now.

@kungfoolfighting
Copy link
Contributor

kungfoolfighting commented Nov 9, 2017

Right My mistake. So It if the ProfileTypeUID didnt change, then it is still the correct string, being "system:rawbutton-toggle". It did work yesterday before the merge and I was happily toggling my lights. I just made a mistake right now. So I had a working item, and now it no longer works.
I will post the exact logger message tonight. but it was something like
"no ProfileFactory found which supports 'itemname_system_rawbutton-toggle_channelname'" I am not exactly certain anymore, but it concatenated parts with underscore and the system_rawbutton_toggle was part of it.
Maybe that helps a bit. But don't spend too much time investigating on this flimsy information before I have verified it.

The exact same message was also printed for my custom enocean profile that I wrote, linked to my custom trigger channel. But that might have potentially other reasons that are unrelated, since this profile didn't work before the merge.

@sjsf
Copy link
Contributor Author

sjsf commented Nov 9, 2017

No, my initial post was wrong (and I corrected it immediately, but that doesn't send out notification mails). The profile ID indeed has changed and got a -switch appended. Sure, just try it out once you find the time and let me know...

@sjsf sjsf added the Core label Nov 9, 2017
@kaikreuzer
Copy link
Contributor

How do you want to deal with @Deprecated void handleUpdate?

-> to be discussed in #4525.

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
@kungfoolfighting
Copy link
Contributor

After I appended the -switch to the profile name, the toggle profile worked again.
I am still not able to make my own profile work.
Do I need to define some XML or something?
What sort of information do I need to provide so you can tell me what I am doing wrong?
None of the break points in any ofthe functions in the profile factory are ever hit.
I have basically just taken the toggle profile as a template and done everything the same way.
When looking into the code I simply cannot find how the registries are being filled with the factories though. It is all obfuscated through the osgi services.

Copy link
Contributor

@kaikreuzer kaikreuzer left a comment

Choose a reason for hiding this comment

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

Looks like a huge simplification for profile implementors (as can be seen at the RawButtonToggleSwitchProfile).

Some small remarks on the code below.


@Override
public void onUpdate(State state) {
this.previousState = state;
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 omit "this" here (as you do in onTrigger as well)

import org.slf4j.LoggerFactory;

/**
* This is the default implementation for a slave profile.
Copy link
Contributor

Choose a reason for hiding this comment

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

slave -> follow

* In contrast to the {@link SystemDefaultProfile} it does not forward any commands to the ThingHandler. Instead, it
* turn {@link State} updates into {@link Command}s (if possible) and then forwards those to the {@link ThingHandler}.
* <p>
* This allows devices to be operated as "slaves" of another one directly, without the need to write any rules.
Copy link
Contributor

Choose a reason for hiding this comment

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

slaves -> followers

}

@Override
public Collection<@NonNull ProfileType> getAll() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of using @NonNull here, shouldn't you use @NonNullByDefault on the class?

*
* @param command
*/
void sendCommandEvent(Command command);
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 remove the word "Event" here - after all, you are sending a command, not an event.

*
* @param state the new {@link State}
*/
void onUpdate(State state);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe better onStateUpdate?

*
*/
@NonNullByDefault
public interface ProfileTypeProvider extends Provider<ProfileType> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this provider rather be similar to ThingTypeProvider etc., i.e. specifically able to provide a profile type for a given locale (such that its label is localisable)?

@@ -19,6 +21,7 @@
* @author Simon Kaufmann - initial contribution and API.
*
*/
@NonNullByDefault
public interface Profile {

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 expect to have a ProfileTypeUID getProfileTypeUID(); method here.


@Override
public void addProviderChangeListener(ProviderChangeListener<@NonNull ProfileType> listener) {
// TODO Auto-generated method stub
Copy link
Contributor

Choose a reason for hiding this comment

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

replace or delete comment


@Override
public void removeProviderChangeListener(ProviderChangeListener<@NonNull ProfileType> listener) {
// TODO Auto-generated method stub
Copy link
Contributor

Choose a reason for hiding this comment

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

replace or delete comment

* renamed profile methods
* made provider/registry obey obey localization
  by following the example of ThingTypeProvider
* fixed a bug in the provider registration
* fixed several typos

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
@@ -24,4 +25,13 @@
@NonNullByDefault
public interface Profile {

ProfileTypeUID getProfileTypeUID();
Copy link
Contributor

Choose a reason for hiding this comment

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

Would you also spend it a single line of JavaDoc? :-)

@kaikreuzer kaikreuzer merged commit 9cddf01 into eclipse-archived:master Nov 10, 2017
@sjsf sjsf deleted the profileAPISimplification branch November 10, 2017 15:05
@maggu2810
Copy link
Contributor

I see several non-null violations

  • Identifiable<T> is using @NonNullByDefault
  • ProfileType extends Identifiable<ProfileTypeUID> and is using @NonNullByDefault
  • StateProfileType extends ProfileType and is using @NonNullByDefault
  • SystemProfiles contains a new annonymous StateProfileType implementations and does not use @NonNullByDefault

@sjsf sjsf mentioned this pull request Nov 13, 2017
sjsf pushed a commit that referenced this pull request Nov 13, 2017
Related to: #4516 (comment)
Signed-off-by: Markus Rathgeb <maggu2810@gmail.com>
@sjsf sjsf mentioned this pull request Nov 14, 2017
@kaikreuzer kaikreuzer added this to the 0.9.0 milestone Nov 30, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants