Skip to content

Commit

Permalink
0.24.0
Browse files Browse the repository at this point in the history
- Lists and subscriptions retained after being locally closed, in case objects are added back.
  • Loading branch information
Aaron committed May 21, 2020
1 parent 00b3e37 commit 99438fe
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 98 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ subprojects {
apply plugin: 'java-library'
apply plugin: 'maven'

version = '0.23.2'
version = '0.24.0'
sourceCompatibility = 1.7
targetCompatibility = 1.7

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ public ListResponse(DSLink link, SubscriptionManager manager,
}

public void childUpdate(Node child, boolean removed) {
if (removed) {
manager.removePathSub(child);
}

JsonArray updates = new JsonArray();
updates.add(getChildUpdate(child, removed));

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

public void nodeCreated(Node node) {
public void nodeAdded(Node node) {
this.node = node;
link.getWriter().writeResponse(getJsonResponse(null));
}

public void nodeRemoved() {
this.node = null;
link.getWriter().writeResponse(getJsonResponse(null));
}

@Override
public void populate(JsonObject in) {
JsonArray updates = in.get("updates");
Expand Down
84 changes: 51 additions & 33 deletions sdk/dslink/src/main/java/org/dsa/iot/dslink/node/Node.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package org.dsa.iot.dslink.node;

import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.dsa.iot.dslink.link.Linkable;
import org.dsa.iot.dslink.node.NodeListener.ValueUpdate;
import org.dsa.iot.dslink.node.actions.Action;
Expand All @@ -9,19 +18,15 @@
import org.dsa.iot.dslink.serializer.SerializationManager;
import org.dsa.iot.dslink.util.StringUtils;

import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
* Contains information about a node and its data.
*
* @author Samuel Grenier
*/
public class Node {

private static final char[] BANNED_CHARS = new char[] {
'%', '.', '/', '\\', '?', '*', ':', '|', '<', '>', '$', '@', ','
private static final char[] BANNED_CHARS = new char[]{
'%', '.', '/', '\\', '?', '*', ':', '|', '<', '>', '$', '@', ','
};

private final Object roConfigLock = new Object();
Expand Down Expand Up @@ -58,15 +63,16 @@ public class Node {
private Set<String> interfaces;
private Action action;
private char[] pass;

boolean building = false;

private boolean shouldPostCachedValue = true;

/**
* Constructs a node object.
*
* @param name Name of the node
* @param parent Parent of this node
* @param link Linkable class the node is handled on
* @param link Linkable class the node is handled on
*/
public Node(String name, Node parent, Linkable link) {
this(name, parent, link, true);
Expand Down Expand Up @@ -100,7 +106,7 @@ public Node(String name, Node parent, Linkable link, boolean shouldEncodeName) {

/**
* @return Parent of this node, can be null if the parent was garbage
* collected or there is no parent.
* collected or there is no parent.
*/
public Node getParent() {
return parent.get();
Expand Down Expand Up @@ -244,15 +250,15 @@ public void setValue(Value value, boolean externalSource) {
}

/**
* @param value Value to set.
* @param value Value to set.
* @param externalSource Whether the value was set from an external source
* like an action that got invoked.
* @param publish Whether to allow a publish to the network.
* @param publish Whether to allow a publish to the network.
* @return Whether a value was actually set.
*/
protected boolean setValue(Value value,
boolean externalSource,
boolean publish) {
boolean externalSource,
boolean publish) {
ValueType type = valueType;
if (type == null) {
if (this.value != null) {
Expand Down Expand Up @@ -372,24 +378,24 @@ public void setWritable(Writable writable) {
public Writable getWritable() {
return writable;
}

/**
* @return Whether the node's value should automatically
* be posted in response to a subscription request.
* @return Whether the node's value should automatically
* be posted in response to a subscription request.
*/
public boolean shouldPostCachedValue() {
return shouldPostCachedValue;
return shouldPostCachedValue;
}

/**
* @param should Whether the node's value should
* automatically be posted in response to a
* @param should Whether the node's value should
* automatically be posted in response to a
* subscription request. Defaults to true.
*/
public void setShouldPostCachedValue(boolean should) {
shouldPostCachedValue = should;
shouldPostCachedValue = should;
}


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

public Iterator<Node> childIterator() {
if (children == null) {
return Collections.emptyIterator();
}
return Collections.unmodifiableCollection(children.values()).iterator();
}

/**
* Clears the children in the node.
*/
Expand Down Expand Up @@ -455,11 +468,12 @@ public NodeBuilder createChild(String name) {
public NodeBuilder createChild(String name, boolean encodeName) {
return createChild(name, profile, encodeName);
}

/**
* Creates a node builder to allow setting up the node data before
* any list subscriptions can be notified.
*
* @param name Name of the child.
* @param name Name of the child.
* @param profile Profile to set on the child
* @return builder
* @see NodeBuilder#build
Expand Down Expand Up @@ -498,27 +512,33 @@ public Node addChild(Node node) {
return children.get(name);
}

SubscriptionManager manager = null;
if (link != null) {
manager = link.getSubscriptionManager();
}

if (node.getProfile() == null) {
node.setProfile(profile);
}
children.put(name, node);
if (manager != null) {
manager.postChildUpdate(node, false);
}
childAdded(node);
if (node.isSerializable()) {
markChanged();
}
return node;
}
}

void childAdded(Node node) {
if (!building) {
SubscriptionManager manager = null;
if (link != null) {
manager = link.getSubscriptionManager();
}
if (manager != null) {
manager.postChildUpdate(node, false);
}
}
}

/**
* Add multiple children at once.
*
* @param nodes Nodes to add.
*/
public void addChildren(List<Node> nodes) {
Expand Down Expand Up @@ -631,8 +651,6 @@ public Node removeChild(String name, boolean encodeName) {

if (manager != null) {
manager.postChildUpdate(child, true);
manager.removeValueSub(child);
manager.removePathSub(child);
}
if (isSerializable()) {
markChanged();
Expand Down Expand Up @@ -836,7 +854,7 @@ public Value getRoConfig(String name) {
/**
* Sets a read-only configuration.
*
* @param name Name of the configuration.
* @param name Name of the configuration.
* @param value Value to set.
* @return The previous value, if any.
*/
Expand Down
116 changes: 62 additions & 54 deletions sdk/dslink/src/main/java/org/dsa/iot/dslink/node/NodeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.dsa.iot.dslink.node.actions.Action;
import org.dsa.iot.dslink.node.value.Value;
import org.dsa.iot.dslink.node.value.ValueType;
Expand Down Expand Up @@ -118,63 +117,72 @@ public Node getChild() {
* The child will then be added to the parent with the set data. Any
* subscriptions will then be notified. Note that the parent must not
* have the child already added or it will just act as a getter.
*
* @return Child node
*/
public Node build() {
Node node = parent.addChild(child);
// addChild can be used as a getter, which is useful in scenarios
// where serialization takes place. However, setting the action
// before building the node may remove the action override, so in
// order to ensure that the action is preserved after serialization,
// the action must be reset on the child node.

node.setSerializable(child.isSerializable());
node.setProfile(child.getProfile());
node.setMetaData(child.getMetaData());
{
// addChild can return a pre-existing node. This results in the
// action being removed. The action is preserved to ensure that
// deserialized nodes can keep their actions without constantly
// being set. The actions are compared to their previous action
// to prevent unnecessary updates to the network.
Action parentAct = node.getAction();
Action childAct = child.getAction();
if (parentAct != childAct) {
node.setAction(child.getAction());
child.building = true;
Node node = null;
try {
node = parent.addChild(child);
// addChild can be used as a getter, which is useful in scenarios
// where serialization takes place. However, setting the action
// before building the node may remove the action override, so in
// order to ensure that the action is preserved after serialization,
// the action must be reset on the child node.

node.setSerializable(child.isSerializable());
node.setProfile(child.getProfile());
node.setMetaData(child.getMetaData());
{
// addChild can return a pre-existing node. This results in the
// action being removed. The action is preserved to ensure that
// deserialized nodes can keep their actions without constantly
// being set. The actions are compared to their previous action
// to prevent unnecessary updates to the network.
Action parentAct = node.getAction();
Action childAct = child.getAction();
if (parentAct != childAct) {
node.setAction(child.getAction());
}
}
}
node.setListener(child.getListener());
node.setDisplayName(child.getDisplayName());
node.setValueType(child.getValueType());
node.setValue(child.getValue());
node.setPassword(child.getPassword());
node.setWritable(child.getWritable());
node.setHasChildren(child.getHasChildren());
node.setHidden(child.isHidden());
node.setSerializable(child.isSerializable());
Map<String, Value> configs = child.getConfigurations();
Map<String, Value> roconfigs = child.getRoConfigurations();
Map<String, Value> attrs = child.getAttributes();
Set<String> interfaces = child.getInterfaces();
if (configs != null) {
for (Entry<String, Value> entry: configs.entrySet()) {
node.setConfig(entry.getKey(), entry.getValue());
}
}
if (roconfigs != null) {
for (Entry<String, Value> entry: roconfigs.entrySet()) {
node.setRoConfig(entry.getKey(), entry.getValue());
}
}
if (attrs != null) {
for (Entry<String, Value> entry: attrs.entrySet()) {
node.setAttribute(entry.getKey(), entry.getValue());
}
}
if (interfaces != null) {
for (String _interface: interfaces) {
node.addInterface(_interface);
}
node.setListener(child.getListener());
node.setDisplayName(child.getDisplayName());
node.setValueType(child.getValueType());
node.setValue(child.getValue());
node.setPassword(child.getPassword());
node.setWritable(child.getWritable());
node.setHasChildren(child.getHasChildren());
node.setHidden(child.isHidden());
node.setSerializable(child.isSerializable());
Map<String, Value> configs = child.getConfigurations();
Map<String, Value> roconfigs = child.getRoConfigurations();
Map<String, Value> attrs = child.getAttributes();
Set<String> interfaces = child.getInterfaces();
if (configs != null) {
for (Entry<String, Value> entry : configs.entrySet()) {
node.setConfig(entry.getKey(), entry.getValue());
}
}
if (roconfigs != null) {
for (Entry<String, Value> entry : roconfigs.entrySet()) {
node.setRoConfig(entry.getKey(), entry.getValue());
}
}
if (attrs != null) {
for (Entry<String, Value> entry : attrs.entrySet()) {
node.setAttribute(entry.getKey(), entry.getValue());
}
}
if (interfaces != null) {
for (String _interface : interfaces) {
node.addInterface(_interface);
}
}
child.building = false;
parent.childAdded(node);
} finally {
child.building = false;
}
return node;
}
Expand Down
Loading

0 comments on commit 99438fe

Please sign in to comment.