-
Notifications
You must be signed in to change notification settings - Fork 89
Expand file tree
/
Copy pathNodeAccessProxy.java
More file actions
195 lines (168 loc) · 5.83 KB
/
NodeAccessProxy.java
File metadata and controls
195 lines (168 loc) · 5.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package nodebox.node;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The NodeAccessProxy makes access to nodes and parameters more
* convenient from expressions. So, instead of writing:
* <p/>
* <pre><code>network.getNode("rect1").getParameter("x").getValue()</code></pre>
* <p/>
* You can write:
* <p/>
* <pre><code>network.rect1.x</code></pre>
* <p/>
* The network and node classes in this example are proxies; they look up
* the node in the nodes dictionary for the network, and return another
* proxy object.
*/
public class NodeAccessProxy implements Map {
private Node node;
private Set<String> keySet;
private Set<WeakReference<Parameter>> markedParameterReferences;
public NodeAccessProxy(Node node) {
this.node = node;
updateKeys();
}
/**
* Initialize the proxy with a access marker that notes which parameters were accessed.
* This marker will be passed to recursive proxies.
*
* @param node the node
* @param markedParameterReferences a list of parameters that were marked.
*/
public NodeAccessProxy(Node node, Set<WeakReference<Parameter>> markedParameterReferences) {
this(node);
this.markedParameterReferences = markedParameterReferences;
}
private void updateKeys() {
keySet = new HashSet<String>();
// keySet is created in reverse order; from global to local scope.
// 1. Add nodes
// 1.1 Add names of the sibling nodes (nodes in the same network as this node.)
if (node.hasParent()) {
for (Node n : node.getParent().getChildren()) {
keySet.add(n.getName());
}
}
// 1.2 Add its child nodes.
for (Node n : node.getChildren()) {
keySet.add(n.getName());
}
// 2. Add parameters
for (Parameter p : node.getParameters()) {
keySet.add(p.getName());
}
// 3. Add ports
for (Port p : node.getPorts()) {
keySet.add(p.getName());
}
// 4. Add reserved words
keySet.add("root");
keySet.add("parent");
keySet.add("node");
}
public Node getNode() {
return node;
}
public int size() {
return keySet.size();
}
public boolean isEmpty() {
return false;
}
public boolean containsKey(Object key) {
if (key == null) return false;
if (!(key instanceof String)) return false;
return keySet.contains((String) key);
}
public boolean containsValue(Object value) {
throw new RuntimeException("Not implemented");
}
/**
* Retrieve the node or parameter value from the proxy.
* Value retrieval happens in a specific order, from local to global:
* <ul>
* <li>Search for reserved words (network, root).</li>
* <li>Search for the name in the parameters of the current node.</li>
* <li>If this node is a network, search in the nodes of the current network. (children)</li>
* <li>If this node is in a network, search for other nodes in that network. (siblings)</li>
* </ul>
*
* @param key the key to search for
* @return a Parameter value or a NodeProxy object.
*/
public Object get(Object key) {
if (key == null) return null;
String k = key.toString();
// First search for reserved words.
if (k.equals("node")) {
return node;
} else if (k.equals("parent")) {
if (node.hasParent()) {
return new NodeAccessProxy(node.getParent(), markedParameterReferences);
} else {
return null;
}
} else if (k.equals("root")) {
if (node.hasParent()) {
return new NodeAccessProxy(node.getParent(), markedParameterReferences);
} else {
// If the node does not have a parent, I am my own root node.
return this;
}
}
// Search the parameters
if (node.hasParameter(k)) {
if (markedParameterReferences != null)
markedParameterReferences.add(new WeakReference<Parameter>(node.getParameter(k)));
return node.getValue(k);
}
// Search the ports
if (node.hasPort(k)) {
return node.getPort(k);
}
// Network searches
// If this is a network, search its nodes first.
if (node.containsChildNode(k)) {
return new NodeAccessProxy(node.getChild(k), markedParameterReferences);
}
// Check the siblings (nodes in this node's network).
if (node.hasParent() && node.getParent().containsChildNode(k)) {
return new NodeAccessProxy(node.getParent().getChild(k), markedParameterReferences);
}
// Don't know what to return.
return null;
}
public Object put(Object key, Object value) {
throw new AssertionError("You cannot change the node access proxy.");
}
public Object remove(Object key) {
throw new AssertionError("You cannot change the node access proxy.");
}
public void putAll(Map t) {
throw new AssertionError("You cannot change the node access proxy.");
}
public void clear() {
throw new AssertionError("You cannot change the node access proxy.");
}
public Set<String> keySet() {
return keySet;
}
public Collection values() {
throw new RuntimeException("Not implemented");
}
public Set entrySet() {
throw new RuntimeException("Not implemented");
}
@Override
public String toString() {
if (node == null) {
return "<Empty proxy>";
} else {
return "<Node " + node.getName() + ">";
}
}
}