-
Notifications
You must be signed in to change notification settings - Fork 787
MqttService: Remove all deprecated methods, rename close to stop. #4173
Conversation
Oops, merge conflicts... |
370b6cf
to
64d48dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it necessary that the host, port, secure flag for a broker connection to be changed after construction?
Wouldn't it be simpler to assign a host and port on construction and create another broker connection object if the host or port should be changed?
Immutable members are thread safe.
What is the behavior if host is changed while connected, what is a reconnect is done etc.
Isn't it common practice that such stuff is only set on construction (e.g. similar to the Java socket)?
Same for the other stuff, too.
If connection parameters that are used on connection establishment only could be changed all the time... it doesn't make the implementation and knowledge what is applied at which done easier.
I agree. The changes would be:
Everything else (qos, reconnect time etc) aren't connection parameters but take effect immediately for all following published messages. |
64d48dd
to
e15627e
Compare
I changed the PR accordingly. I'm just not sure about username and password. Those are technically speaking not connection parameters and can change between stop/start cycles and are optional. |
throw new ConfigurationException("MQTT Broker property 'name' is not provided"); | ||
} | ||
brokerID = brokerID.toLowerCase(); | ||
public synchronized MqttBrokerConnection addBrokerConnection(@NonNull String brokerID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kaikreuzer Do I remember correctly that you allowed @Nullable
on return types to enable checks for the consumer code?
If it is allowed I would prefer to add it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, Nullable is the java standard. I agree that it sometimes makes sense to add it, as a way to document parameters, for instance Integer: A consumer might feel like he always needs to provide a value, even if null
would be absolutely acceptable.
But for return types I would say Nullable is not reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please read #4080
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah a twenty page long discussion doesn't help :) A link or quote of the developer guidelines would convince me of course :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't a developer guidelines about the usage of nullness annotation. At least we didn't fully agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least everything that has been agreed on, should be put in the developer guidelines. Should I open an issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. I have added a summary here:
https://github.com/eclipse/smarthome/wiki/Type-annotations
synchronized (brokerConnections) { | ||
return brokerConnections.get(brokerName.toLowerCase()); | ||
} | ||
public synchronized MqttBrokerConnection getBrokerConnection(String brokerName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other comment about Nullable
on return type.
5ca6321
to
a8d6746
Compare
@maggu2810 Was this PR now ok for you? |
return url; | ||
@Nullable | ||
public Integer getPort() { | ||
return port; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the constructor you state.
* @param port A port or null to select the default port for a secure or insecure connection
So I would assume that a port is choosen now and we could return the explicit set one, the insecure or secure default.
I am pretty sure that a connection uses a port ;)
If the MQTT transport and reconnect is still working (using the non-deprecated methods), all is okay for me. 😉 |
Parts of the nullness fixes could be taken from here: ae1a8ac |
a8d6746
to
f818ccd
Compare
At the moment that means, this service will not be configurable without changes to the "Configuration" class. |
Because my other Mqtt PRs are based on the API changes, introduced here, I will resurrect this PR. I will also adapt it to the service multi-config concept. |
f818ccd
to
9c672af
Compare
@davidgraeff ping me when ready for review. |
@htreu Code-wise it is complete. But travis failed because of another issue, therefore I do not know if if will pass the static code check yet. Could you have a look at the MqttBrokerConnectionServiceInstance file, if I'm using the service-factory in a right way? |
Travis seems to be unrelated. For the MqttBrokerConnectionServiceInstance please have a look at the
The Once you have everything setup correctly Paper UI should allow you to add/edit/remove instances of your service. |
@htreu If have adjusted the PR. Could you have a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @davidgraeff good to see this progressing. Please find my comments inline.
public @Nullable String password; | ||
public @Nullable String clientID; | ||
// MQTT parameters | ||
public BigDecimal qos = BigDecimal.valueOf(MqttBrokerConnection.DEFAULT_QOS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When configuring a new service instance from Paper UI this fails with:
10:36:02.939 WARN o.e.s.c.core.Configuration[:108] - Could not set field value for field 'qos': Can not set java.math.BigDecimal field org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnectionConfig.qos to java.lang.String
java.lang.IllegalArgumentException: Can not set java.math.BigDecimal field org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnectionConfig.qos to java.lang.String
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
at java.lang.reflect.Field.set(Field.java:764)
at org.apache.commons.lang.reflect.FieldUtils.writeField(FieldUtils.java:523)
at org.apache.commons.lang.reflect.FieldUtils.writeField(FieldUtils.java:500)
at org.apache.commons.lang.reflect.FieldUtils.writeField(FieldUtils.java:560)
at org.eclipse.smarthome.config.core.Configuration.as(Configuration.java:105)
at org.eclipse.smarthome.io.transport.mqtt.internal.MqttBrokerConnectionServiceInstance.modified(MqttBrokerConnectionServiceInstance.java:76)
at org.eclipse.smarthome.io.transport.mqtt.internal.MqttBrokerConnectionServiceInstance.activate(MqttBrokerConnectionServiceInstance.java:107)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
I'm not aware of the configuration conversion logic, but maybe Integer
will do?
public Boolean retainMessages = false; | ||
public @Nullable String lastWill; | ||
/** Keepalive in seconds */ | ||
public @Nullable BigDecimal keepAlive; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here as for qos
.
* http://www.eclipse.org/legal/epl-2.0 | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* Copyright (c) 2014-2017 by the respective copyright holders. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just run mvn license:format
on your sources again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I do have to correct license headers myself. mvn license:format
only corrects xml headers for me after 10min of downloading various files (it is time for gradle!). Therefore, If you see another spot, please let the know.
logger.warn("Ignore invalid broker connection configuration: {}", config); | ||
return; | ||
} | ||
assert brokerID != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should already be handled by StringUtils.isBlank(brokerID)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, but at least my eclipse will issue a warning. I'll investigate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The static analyser, used by eclipse, is not recognizing the result of StringUtils.isBlank
. The assert is unfortunately necessary here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove it and ignore the warning. Or add an extra null check to the StringUtils check.
assert brokerID != null; | ||
|
||
// Add connection and make sure it succeeded | ||
assert mqttService != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already checked by line 71 (null check against config and mqttservice).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, but eclipse is issuing a warning. I guess that's because mqttService
is a field variable and the static analyser doesn't guarantee that no concurrent thread or side effect of a method call changes the field. I would leave it for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove and ignore/refactor
* @author David Graeff - Initial contribution | ||
*/ | ||
@Component(immediate = true, service = MqttBrokerConnectionServiceInstanceMarker.class, property = { | ||
Constants.SERVICE_PID + "=org.eclipse.smarthome.magicMultiInstance", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy&paste error?
public final @Nullable String lwtTopic; | ||
public final byte @Nullable [] lwtMessage; | ||
public final @Nullable Integer lwtQos; | ||
public final @Nullable Boolean lwtRetain; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review the latest changes @maggu2810 did on the LWT configuration. It is now possible to either pass the encoded String with topic:message:qos:retained
or provide all values in separate fields (see #5231).
<description>Hostname or IP of the broker</description> | ||
<default></default> | ||
</parameter> | ||
<parameter name="host" type="integer" required="false"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
name should be host
|
||
/** | ||
* Return the brokerID of this connection. This is either the name or host:port(:s). | ||
* This method might return null, if none of the parameters is set. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The method does actually not return null but the empty String is nothing is configured.
@htreu Issues addressed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Some more comment inline.
Also: Again I get the following exception:
java.lang.IllegalArgumentException: Can not set java.lang.Integer field org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnectionConfig.lwtQos to java.lang.String
<advanced>true</advanced> | ||
</parameter-group> | ||
|
||
<parameter name="name" type="text" required="false" groupName="group_connection"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please run auto formatter once.
<default>false</default> | ||
</parameter> | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty line
e.getMessage(), e.getReasonCode(), | ||
(e.getCause() == null ? "Unknown" : e.getCause().getMessage())); | ||
public synchronized void connectionLost(@Nullable Throwable exception) { | ||
assert exception != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exception
being null seems to be a legit case. Its way too hard to throw errors here.
We do not use assert
in ESH at all: Assertions need to be switched on during compilation what we don't do. Thus they will be removed from the resulting class files. And in this particular case it is hiding a NPE when exception
actually is null.
Please review other occurrences and replace them by throwing IllegalArgumentException or IllegalStateException.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked with the documentation. All parameters on this interface are meant to be non null. The annotations are just missing and assert is basically used to compensate. I have added some comments. I do know that assert's are not compiled into bytecode in our case, it is more of a compiler and IDE hint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assertions need to be switched on during compilation what we don't do.
That's not correct.
assertions could be enabled at runtime to use additional checks (e.g. in the development phase) that are not enabled default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see (http://etutorials.org/Programming/Java+performance+tuning/Chapter+6.+Exceptions+Assertions+Casts+and+Variables/6.2+Assertions/). So it actually imposes a runtime overhead in contrast to C/C++. I'll use local variables then to get rid of the warnings.
this.secure = secure; | ||
if (clientId == null) { | ||
clientId = MqttClient.generateClientId(); | ||
assert clientId != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove or refactor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some asserts can not be removed in my eclipse setup, which was done by oomph and the official installer. I get errors like "Null type mismatch (type annotations): required '@nonnull String' but this expression has type '@nullable String'. The problem severity defaults to "error" for those null checks.
logger.warn("Ignore invalid broker connection configuration: {}", config); | ||
return; | ||
} | ||
assert brokerID != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove it and ignore the warning. Or add an extra null check to the StringUtils check.
assert brokerID != null; | ||
|
||
// Add connection and make sure it succeeded | ||
assert mqttService != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove and ignore/refactor
return; | ||
} | ||
// Start connection | ||
assert connection != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove and ignore/refactor
I have no idea, why you get "java.lang.IllegalArgumentException: Can not set java.lang.Integer field org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnectionConfig.lwtQos to java.lang.String" to be honest. The conf desc xml says |
2b32193
to
b09c65c
Compare
I don't understand the exception either. Does it work for you?
|
See: #4625 |
The reason for the IllegalArgumentException is this:
|
I have addressed the Configuration class shortcoming here: #5262 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some cosmetics left. And the question, if lwt should also be configurable by a single line as in the past (see inline comment).
<description>Broker username</description> | ||
<default /> | ||
</parameter> | ||
<parameter name="password" type="text" required="false" groupName="group_connection"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please give this parameter the context password
.
} | ||
|
||
@Override | ||
public void deliveryComplete(IMqttDeliveryToken token) { | ||
public void deliveryComplete(@Nullable IMqttDeliveryToken token_) { | ||
IMqttDeliveryToken token = (@NonNull IMqttDeliveryToken) token_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like an accident waiting to happen :-) Please simply null-check here.
final List<MqttMessageSubscriber> consumerList = entry.getValue(); | ||
|
||
public void messageArrived(@Nullable String topic_, @Nullable MqttMessage message_) { | ||
byte[] payload = ((@NonNull MqttMessage) message_).getPayload(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I get what you are doing here. Instead of defining the methods args @Nullable
and do the cast here you may add @NonNullByDefault({})
at ClientCallbacks
class level. This will "switch off" null annotation checks in this class. It hurts the eyes a little less then casting @Nullabel
to @NonNull
.
/** Keepalive in seconds */ | ||
public @Nullable Integer keepAlive; | ||
// Last will parameters | ||
public @Nullable String lwtTopic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now the "old" configuration of lwt is not supported anymore. With #5231 @maggu2810 made sure both options could be used.
I thinks its fine that the UI (config description) only provides the single fields. But text based configuration may depend on the single line config. wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is a API brake, code-wise as well as configuration-wise. Remember that we used the dot syntax before to express multiple mqtt instances and we use osgi service factories with a config file each now. Any user of this service (which I doubt there are any, because we provide no means to use Mqtt really) need to migrate anyway ^^.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maggu2810 fine for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is okay for me to drop the old way to configure the LWT.
I am pretty sure there are guys the use this service. There has been one that inspired me to implement that change (to support a more generic topic and payload) and I am using that service, too. Already two of them. 😉 But as @davidgraeff also pointed out, changes in its usage needs to be done regardless if we keep this field or not, so I would prefer to remove old stuff and stop maintaining it on this change and all the other ones that will come some time.
@htreu Done |
Strange: Travis complains about
|
Hm, but why. A fast lookup on google let me find this example: And another hm. It does of course compile... in eclipse. That's the main reason btw why google migrated for Android from eclipe to IDEA+gradle, to always use one build system. |
My guess is, that |
That artifact is used for the annotations on a Maven build (see
This artifact itself uses the
Have a look at Release 4 Version 4.3 - Annotation Type Component: |
Thanks @maggu2810. I always searched our org.eclipse.osgi.services-3.6.0 dependency where String[] is defined. Where do we define the OSGi DS Annotation version to be used? Or: who is right? the maven dependency or the IDE dependency?
Yes, I just observed that in the annotation processor sources. |
The development guidelines states: "The minimum OSGi framework version supported is OSGi R4.2, no newer features must be used." The OSGi stuff that is available in the Eclipse IDE provides much more recent versions, so in this case the Maven one is "more correct" as it uses an older version of the annotations. Another example: In the Eclipse IDE you can also annotate a field in a component using |
Thanks. And to complete the picture (since you referenced R4V4.3) we can use these because no runtime support is needed (I see no *.annotation package in the 4.2 API). |
Which one ("org.eclipse annotations") do you mean? |
Guys :) I changed the configurationpid to a simple string and would like to go on with this PR. |
* eclipse-archived#4173 changes some APIs, adapt to those. * Remove the broker connection thing, we are going to use the one defined in eclipse-archived#3839 * Remove all discovery stuff Signed-off-by: David Gräff <david.graeff@web.de>
@davidgraeff agreed :-)
Again strange that the IDE misses to show the error. |
Because the IDE has more background knowledge. Look at the code in question, especially
|
come on, don't let travis win!
After correcting this there is also one test left failing:
You now always initialise the port. Now the test assumption is false. |
…more. * Remove name from MqttBrokerConnection. This is only necessary for the MqttService. Consumers of MqttBrokerConnection should not be bothered with that detail. * Remove textConfigured flag. Again this is not interesting for anything outside MqttService. * Don't parse configuration parameters ourself, but use a configuration values class instead. * Adapt to Nullable usage. * Mqtt: Introduce service factory service MqttBrokerConnectionServiceInstance * ESH compatible implementation of the service factory pattern including a config description for GUIs * Add MqttService.setLastWill method. Fixes eclipse-archived#5162 Signed-off-by: David Graeff <david.graeff@web.de>
4713b81
to
d4ad8c1
Compare
@htreu Tests corrected. And squashed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Travis is happy and so am I :-)
Thanks @davidgraeff.
This PR prepares the io.transport.mqtt bundle for the discussed MQTT architecture.
name
from MqttBrokerConnection. This is only necessary for the MqttService.Consumers of MqttBrokerConnection should not be bothered with this detail.
name
.textualConfigured
flag. Again this is not interesting for anything outside MqttService.API break:
Config interface break:
Documentation
MqttService
and its purpose.Fixes #4170
Signed-off-by: David Gräff david.graeff@web.de