Skip to content

Commit 99438fe

Browse files
author
Aaron
committedMay 21, 2020
0.24.0
- Lists and subscriptions retained after being locally closed, in case objects are added back.
1 parent 00b3e37 commit 99438fe

File tree

5 files changed

+151
-98
lines changed

5 files changed

+151
-98
lines changed
 

‎build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ subprojects {
77
apply plugin: 'java-library'
88
apply plugin: 'maven'
99

10-
version = '0.23.2'
10+
version = '0.24.0'
1111
sourceCompatibility = 1.7
1212
targetCompatibility = 1.7
1313

‎sdk/dslink/src/main/java/org/dsa/iot/dslink/methods/responses/ListResponse.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ public ListResponse(DSLink link, SubscriptionManager manager,
5656
}
5757

5858
public void childUpdate(Node child, boolean removed) {
59-
if (removed) {
60-
manager.removePathSub(child);
61-
}
62-
6359
JsonArray updates = new JsonArray();
6460
updates.add(getChildUpdate(child, removed));
6561

@@ -276,11 +272,16 @@ public void multiChildrenUpdate(List<Node> children) {
276272
link.getWriter().writeResponse(resp);
277273
}
278274

279-
public void nodeCreated(Node node) {
275+
public void nodeAdded(Node node) {
280276
this.node = node;
281277
link.getWriter().writeResponse(getJsonResponse(null));
282278
}
283279

280+
public void nodeRemoved() {
281+
this.node = null;
282+
link.getWriter().writeResponse(getJsonResponse(null));
283+
}
284+
284285
@Override
285286
public void populate(JsonObject in) {
286287
JsonArray updates = in.get("updates");

‎sdk/dslink/src/main/java/org/dsa/iot/dslink/node/Node.java

+51-33
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package org.dsa.iot.dslink.node;
22

3+
import java.lang.ref.WeakReference;
4+
import java.util.Collections;
5+
import java.util.HashMap;
6+
import java.util.HashSet;
7+
import java.util.Iterator;
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.Set;
11+
import java.util.concurrent.ConcurrentHashMap;
312
import org.dsa.iot.dslink.link.Linkable;
413
import org.dsa.iot.dslink.node.NodeListener.ValueUpdate;
514
import org.dsa.iot.dslink.node.actions.Action;
@@ -9,19 +18,15 @@
918
import org.dsa.iot.dslink.serializer.SerializationManager;
1019
import org.dsa.iot.dslink.util.StringUtils;
1120

12-
import java.lang.ref.WeakReference;
13-
import java.util.*;
14-
import java.util.concurrent.ConcurrentHashMap;
15-
1621
/**
1722
* Contains information about a node and its data.
1823
*
1924
* @author Samuel Grenier
2025
*/
2126
public class Node {
2227

23-
private static final char[] BANNED_CHARS = new char[] {
24-
'%', '.', '/', '\\', '?', '*', ':', '|', '<', '>', '$', '@', ','
28+
private static final char[] BANNED_CHARS = new char[]{
29+
'%', '.', '/', '\\', '?', '*', ':', '|', '<', '>', '$', '@', ','
2530
};
2631

2732
private final Object roConfigLock = new Object();
@@ -58,15 +63,16 @@ public class Node {
5863
private Set<String> interfaces;
5964
private Action action;
6065
private char[] pass;
61-
66+
boolean building = false;
67+
6268
private boolean shouldPostCachedValue = true;
6369

6470
/**
6571
* Constructs a node object.
6672
*
6773
* @param name Name of the node
6874
* @param parent Parent of this node
69-
* @param link Linkable class the node is handled on
75+
* @param link Linkable class the node is handled on
7076
*/
7177
public Node(String name, Node parent, Linkable link) {
7278
this(name, parent, link, true);
@@ -100,7 +106,7 @@ public Node(String name, Node parent, Linkable link, boolean shouldEncodeName) {
100106

101107
/**
102108
* @return Parent of this node, can be null if the parent was garbage
103-
* collected or there is no parent.
109+
* collected or there is no parent.
104110
*/
105111
public Node getParent() {
106112
return parent.get();
@@ -244,15 +250,15 @@ public void setValue(Value value, boolean externalSource) {
244250
}
245251

246252
/**
247-
* @param value Value to set.
253+
* @param value Value to set.
248254
* @param externalSource Whether the value was set from an external source
249255
* like an action that got invoked.
250-
* @param publish Whether to allow a publish to the network.
256+
* @param publish Whether to allow a publish to the network.
251257
* @return Whether a value was actually set.
252258
*/
253259
protected boolean setValue(Value value,
254-
boolean externalSource,
255-
boolean publish) {
260+
boolean externalSource,
261+
boolean publish) {
256262
ValueType type = valueType;
257263
if (type == null) {
258264
if (this.value != null) {
@@ -372,24 +378,24 @@ public void setWritable(Writable writable) {
372378
public Writable getWritable() {
373379
return writable;
374380
}
375-
381+
376382
/**
377-
* @return Whether the node's value should automatically
378-
* be posted in response to a subscription request.
383+
* @return Whether the node's value should automatically
384+
* be posted in response to a subscription request.
379385
*/
380386
public boolean shouldPostCachedValue() {
381-
return shouldPostCachedValue;
387+
return shouldPostCachedValue;
382388
}
383389

384390
/**
385-
* @param should Whether the node's value should
386-
* automatically be posted in response to a
391+
* @param should Whether the node's value should
392+
* automatically be posted in response to a
387393
* subscription request. Defaults to true.
388394
*/
389395
public void setShouldPostCachedValue(boolean should) {
390-
shouldPostCachedValue = should;
396+
shouldPostCachedValue = should;
391397
}
392-
398+
393399

394400
/**
395401
* @return Children of the node, can be null
@@ -399,6 +405,13 @@ public Map<String, Node> getChildren() {
399405
return children != null ? Collections.unmodifiableMap(children) : null;
400406
}
401407

408+
public Iterator<Node> childIterator() {
409+
if (children == null) {
410+
return Collections.emptyIterator();
411+
}
412+
return Collections.unmodifiableCollection(children.values()).iterator();
413+
}
414+
402415
/**
403416
* Clears the children in the node.
404417
*/
@@ -455,11 +468,12 @@ public NodeBuilder createChild(String name) {
455468
public NodeBuilder createChild(String name, boolean encodeName) {
456469
return createChild(name, profile, encodeName);
457470
}
471+
458472
/**
459473
* Creates a node builder to allow setting up the node data before
460474
* any list subscriptions can be notified.
461475
*
462-
* @param name Name of the child.
476+
* @param name Name of the child.
463477
* @param profile Profile to set on the child
464478
* @return builder
465479
* @see NodeBuilder#build
@@ -498,27 +512,33 @@ public Node addChild(Node node) {
498512
return children.get(name);
499513
}
500514

501-
SubscriptionManager manager = null;
502-
if (link != null) {
503-
manager = link.getSubscriptionManager();
504-
}
505-
506515
if (node.getProfile() == null) {
507516
node.setProfile(profile);
508517
}
509518
children.put(name, node);
510-
if (manager != null) {
511-
manager.postChildUpdate(node, false);
512-
}
519+
childAdded(node);
513520
if (node.isSerializable()) {
514521
markChanged();
515522
}
516523
return node;
517524
}
518525
}
519526

527+
void childAdded(Node node) {
528+
if (!building) {
529+
SubscriptionManager manager = null;
530+
if (link != null) {
531+
manager = link.getSubscriptionManager();
532+
}
533+
if (manager != null) {
534+
manager.postChildUpdate(node, false);
535+
}
536+
}
537+
}
538+
520539
/**
521540
* Add multiple children at once.
541+
*
522542
* @param nodes Nodes to add.
523543
*/
524544
public void addChildren(List<Node> nodes) {
@@ -631,8 +651,6 @@ public Node removeChild(String name, boolean encodeName) {
631651

632652
if (manager != null) {
633653
manager.postChildUpdate(child, true);
634-
manager.removeValueSub(child);
635-
manager.removePathSub(child);
636654
}
637655
if (isSerializable()) {
638656
markChanged();
@@ -836,7 +854,7 @@ public Value getRoConfig(String name) {
836854
/**
837855
* Sets a read-only configuration.
838856
*
839-
* @param name Name of the configuration.
857+
* @param name Name of the configuration.
840858
* @param value Value to set.
841859
* @return The previous value, if any.
842860
*/

‎sdk/dslink/src/main/java/org/dsa/iot/dslink/node/NodeBuilder.java

+62-54
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.util.Map;
44
import java.util.Map.Entry;
55
import java.util.Set;
6-
76
import org.dsa.iot.dslink.node.actions.Action;
87
import org.dsa.iot.dslink.node.value.Value;
98
import org.dsa.iot.dslink.node.value.ValueType;
@@ -118,63 +117,72 @@ public Node getChild() {
118117
* The child will then be added to the parent with the set data. Any
119118
* subscriptions will then be notified. Note that the parent must not
120119
* have the child already added or it will just act as a getter.
120+
*
121121
* @return Child node
122122
*/
123123
public Node build() {
124-
Node node = parent.addChild(child);
125-
// addChild can be used as a getter, which is useful in scenarios
126-
// where serialization takes place. However, setting the action
127-
// before building the node may remove the action override, so in
128-
// order to ensure that the action is preserved after serialization,
129-
// the action must be reset on the child node.
130-
131-
node.setSerializable(child.isSerializable());
132-
node.setProfile(child.getProfile());
133-
node.setMetaData(child.getMetaData());
134-
{
135-
// addChild can return a pre-existing node. This results in the
136-
// action being removed. The action is preserved to ensure that
137-
// deserialized nodes can keep their actions without constantly
138-
// being set. The actions are compared to their previous action
139-
// to prevent unnecessary updates to the network.
140-
Action parentAct = node.getAction();
141-
Action childAct = child.getAction();
142-
if (parentAct != childAct) {
143-
node.setAction(child.getAction());
124+
child.building = true;
125+
Node node = null;
126+
try {
127+
node = parent.addChild(child);
128+
// addChild can be used as a getter, which is useful in scenarios
129+
// where serialization takes place. However, setting the action
130+
// before building the node may remove the action override, so in
131+
// order to ensure that the action is preserved after serialization,
132+
// the action must be reset on the child node.
133+
134+
node.setSerializable(child.isSerializable());
135+
node.setProfile(child.getProfile());
136+
node.setMetaData(child.getMetaData());
137+
{
138+
// addChild can return a pre-existing node. This results in the
139+
// action being removed. The action is preserved to ensure that
140+
// deserialized nodes can keep their actions without constantly
141+
// being set. The actions are compared to their previous action
142+
// to prevent unnecessary updates to the network.
143+
Action parentAct = node.getAction();
144+
Action childAct = child.getAction();
145+
if (parentAct != childAct) {
146+
node.setAction(child.getAction());
147+
}
144148
}
145-
}
146-
node.setListener(child.getListener());
147-
node.setDisplayName(child.getDisplayName());
148-
node.setValueType(child.getValueType());
149-
node.setValue(child.getValue());
150-
node.setPassword(child.getPassword());
151-
node.setWritable(child.getWritable());
152-
node.setHasChildren(child.getHasChildren());
153-
node.setHidden(child.isHidden());
154-
node.setSerializable(child.isSerializable());
155-
Map<String, Value> configs = child.getConfigurations();
156-
Map<String, Value> roconfigs = child.getRoConfigurations();
157-
Map<String, Value> attrs = child.getAttributes();
158-
Set<String> interfaces = child.getInterfaces();
159-
if (configs != null) {
160-
for (Entry<String, Value> entry: configs.entrySet()) {
161-
node.setConfig(entry.getKey(), entry.getValue());
162-
}
163-
}
164-
if (roconfigs != null) {
165-
for (Entry<String, Value> entry: roconfigs.entrySet()) {
166-
node.setRoConfig(entry.getKey(), entry.getValue());
167-
}
168-
}
169-
if (attrs != null) {
170-
for (Entry<String, Value> entry: attrs.entrySet()) {
171-
node.setAttribute(entry.getKey(), entry.getValue());
172-
}
173-
}
174-
if (interfaces != null) {
175-
for (String _interface: interfaces) {
176-
node.addInterface(_interface);
177-
}
149+
node.setListener(child.getListener());
150+
node.setDisplayName(child.getDisplayName());
151+
node.setValueType(child.getValueType());
152+
node.setValue(child.getValue());
153+
node.setPassword(child.getPassword());
154+
node.setWritable(child.getWritable());
155+
node.setHasChildren(child.getHasChildren());
156+
node.setHidden(child.isHidden());
157+
node.setSerializable(child.isSerializable());
158+
Map<String, Value> configs = child.getConfigurations();
159+
Map<String, Value> roconfigs = child.getRoConfigurations();
160+
Map<String, Value> attrs = child.getAttributes();
161+
Set<String> interfaces = child.getInterfaces();
162+
if (configs != null) {
163+
for (Entry<String, Value> entry : configs.entrySet()) {
164+
node.setConfig(entry.getKey(), entry.getValue());
165+
}
166+
}
167+
if (roconfigs != null) {
168+
for (Entry<String, Value> entry : roconfigs.entrySet()) {
169+
node.setRoConfig(entry.getKey(), entry.getValue());
170+
}
171+
}
172+
if (attrs != null) {
173+
for (Entry<String, Value> entry : attrs.entrySet()) {
174+
node.setAttribute(entry.getKey(), entry.getValue());
175+
}
176+
}
177+
if (interfaces != null) {
178+
for (String _interface : interfaces) {
179+
node.addInterface(_interface);
180+
}
181+
}
182+
child.building = false;
183+
parent.childAdded(node);
184+
} finally {
185+
child.building = false;
178186
}
179187
return node;
180188
}

0 commit comments

Comments
 (0)