-
Notifications
You must be signed in to change notification settings - Fork 409
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
Multi-timestamp Send implementation #1217
Multi-timestamp Send implementation #1217
Conversation
2ee77ba
to
c2137a8
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.
A first review without looking at small details.
/** | ||
* Get all collected nodes represented as {@link LwM2mPath}-{@link LwM2mNode} map. | ||
*/ | ||
Map<LwM2mPath, LwM2mNode> getNodes(); |
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 get what returns getNodes()
?
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 TimestampedLwM2mNodes is collection of nodes with information about path and timestamp. This methods just returns nodes (path map). Should be called getAllNodes()? I'm not quite understand the problem.
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.
My concern is that I'm not sure what means "all nodes".
Eg. :
t1 => path1 => nodeValue1a
t1 => path2 => nodeValue2
t2 => path1 => nodeValue1b
t3 => path1 => nodeValue1c
In this case, with a map from path to node, we will have only 1 value for path1 or I missed something ? so this is not really all node ? or ?
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.
My intention in this case is provide way to get nodes as usual, ignoring timestamps (if you don't care about timestamps). In other case you can use getTimestampedNodes(), getNodesForTimestamp() to be time-aware. What name should I use to improve readability or give more context? And maybe javadoc is not enough decriptive?
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.
Ok I get it.
So I guess if you don't care about timestamped you want to get more recent value right ? So maybe this should be added in javadoc and/or the method is renamed in getMostRecentNodes() (or something like this) ?
Bonus quesiton :
Is it possible to have timestamped value mixed with "not timestamped" value ?
If it is possible, null timestamped value is more or less recent ?
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 want to avoid the "most recent" phrase because it suggest to gets only "t3 => path1 => nodeValue1c"
value from example above (because it's really most recent). My intention is to ignore timestamp segregation. Of course in example above we have conflicts and we have to choose one of "nodeValue1a", "nodeValue1b", "nodeValue1c" and the last one seems to be most appropriate indeed.
Is it possible to have timestamped value mixed with "not timestamped" value ?
If client send this kind of data and it's technically valid, the server should be able to handle it. So the answer is "yes"
If it is possible, null timestamped value is more or less recent ?
It's undefined by definition, and until you use methods getTimestampedNodes()
, getNodesForTimestamp()
and getTimestamps()
it doesn't really matter (the consumer implementation have ability to manage the order). I had to provide some order for technical reasons (default TreeMap doesn't support null keys), so I recreated Comparator.nullsFirst() equivalent from java 8 (it's not copy paste!).
Maybe I should add some tests to valid order in cases pointed above?
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 want to avoid the "most recent" phrase because it suggest to gets only "t3 => path1 => nodeValue1c" value from example above (because it's really most recent). My intention is to ignore timestamp segregation. Of course in example above we have conflicts and we have to choose one of "nodeValue1a", "nodeValue1b", "nodeValue1c" and the last one seems to be most appropriate indeed.
I understand but this seems more confusing to me to not explained how returned nodes are selected.
Even if the wording "most recent" is not crystal clear it gives at least some hints about the behavior which is only most recent value of each node is selected.
Anyway, not a big deal if the method name does not contains the "most recent" idea but I think at least the javadoc should clearly define the behavior.
It's undefined by definition, and until you use methods getTimestampedNodes(), getNodesForTimestamp() and getTimestamps() it doesn't really matter (the consumer implementation have ability to manage the order). I had to provide some order for technical reasons (default TreeMap doesn't support null keys), so I recreated Comparator.nullsFirst() equivalent from java 8 (it's not copy paste!).
I'm a bit confused by the idea because I don't know how this could be undefined.
At implementation level we must decide which node we keep in this path=>node map when we have something like :
E.g. :
null => path 1 => nodeValue1a
t1 => path 1 => nodeValue1b
t2 => path 1 => nodeValue1c
I guess null
can be consider as now and so probably the most recent one and timestamp is for past value. (future value does not really make sense 🤔 )
Maybe I should add some tests to valid order in cases pointed above?
It sounds a good idea.
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'm a bit confused by the idea because I don't know how this could be undefined.
I mean this order is nowhere directly described, so we have to establish how order null timestamp.
I guess null can be consider as now and so probably the most recent one and timestamp is for past value.
Ok for me. I've updated implementation to take null timestamp as the latest.
/** | ||
* The default implementation of {@link TimestampedLwM2mNodes} | ||
*/ | ||
public class TimestampedLwM2mNodesImpl implements TimestampedLwM2mNodes { |
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.
Do we really need a Interface + class (impl) ?
Currently the LwM2mNode hierarchy and TimestampedLwM2mNode are just class.
Maybe for consistency we should just have a class for TimestampedLwM2mNodes too ? unless there is a real need to create a dedicated interface ?
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 core functionality is extracted as interface and - as you ask before - there is read only. The concrete implementation have some options that allow to create and manipulate instance (add elements, create instance etc). There is functional separation where read only interface should be used in most cases and concrete implementation to create one.
return timestampedPathNodesMap.keySet(); | ||
} | ||
|
||
public void put(Long timestamp, LwM2mPath path, LwM2mNode node) { |
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.
TimestampedLwM2mNodesImpl seems not to be immutable.
See #1192 (comment)
If possible I would prefer to make it immutable.
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.
Immutable is TimestampedLwM2mNodes interface. Concrete implementation should not be exposed outside.
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.
Not a big deal but I think we don't understand Immutable in a same way.
I understand that immutable means that an object can not be modified once it is created.
So this is not really applicable to an interface because an interface can not be created.
And in this case, the object behind the interface can be modified by using cast.
Anyway, you can let this point aside if you want :-)
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 many ways to achieve the goal. I changed the implementation to make TimestampedLwM2mNodes immutable (without interface).
public TimestampedLwM2mNodes decodeMultiTimestampedNodes(byte[] content, ContentFormat format, | ||
LwM2mModel model) throws CodecException { | ||
Map<Long, LwM2mNode> timestampedNodes = getExampleTimestampedNodes(); | ||
|
||
TimestampedLwM2mNodesImpl data = new TimestampedLwM2mNodesImpl(); | ||
for (Map.Entry<Long, LwM2mNode> entry : timestampedNodes.entrySet()) { | ||
data.put(entry.getKey(), getExamplePath(), entry.getValue()); | ||
} | ||
|
||
return data; | ||
} | ||
|
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'm not sure I get the point here because it seems that the server will ignore the byte[] content
?
Should we rather hack the client instead of server ?
I mean the purpose of this PR is to add the feature at server side without the client side.
So I can understand that we hack the client to make it send a timestampted payload but if we hack the server I'm not sure what we are testing 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.
It was the starting point for searching solution, checking what happen if we get already decoded nodes in SendResource.handlePOST(). Where is no direct tests for SendResource and SendHandler so I just used integration tests to check this layer. I didn't hack the client because there was no real implementation of encoder/decoder yet.
But for now this test seems obsolete and it looks like it's actually better to modify client side indeed.
I'll check if I can provide better solution.
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.
If you want a kind of hack you can look at https://github.com/eclipse/leshan/blob/master/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/observe/ObserveTimeStampTest.java
Another solution, If you plan to add support of this at client side soon, we can wait for client implementation before to add Integration Test ?
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.
In the meantime I modified test to hack client side rather than the server side
ca77907
to
0ca697d
Compare
@Michal-Wadowski thx for last changes. |
This is included in #1218. |
The solution for #1192