Skip to content

Commit cf57b41

Browse files
authored
0.48.0
- Fix broken actions - Gradle update - Refactor simpleinvokehandler - New action unit tests
2 parents 0dacf70 + 80e3807 commit cf57b41

File tree

16 files changed

+895
-113
lines changed

16 files changed

+895
-113
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ subprojects {
55
apply plugin: 'maven'
66

77
group 'org.iot-dsa'
8-
version '0.47.0'
8+
version '0.48.0'
99

1010
sourceCompatibility = 1.8
1111
targetCompatibility = 1.8
@@ -47,5 +47,5 @@ if (JavaVersion.current().isJava8Compatible()) {
4747
}
4848

4949
wrapper {
50-
gradleVersion = '4.10.2'
50+
gradleVersion = '5.0'
5151
}

dslink-v2/src/main/java/com/acuity/iot/dsa/dslink/protocol/responder/DSInboundInvoke.java

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,25 +157,26 @@ public void run() {
157157
DSIResponder responder = (DSIResponder) path.getTarget();
158158
setPath(path.getPath());
159159
result = responder.onInvoke(this);
160-
}
161-
DSInfo info = path.getTargetInfo();
162-
if (!info.isAction()) {
163-
throw new DSRequestException("Not an action " + path.getPath());
164-
}
165-
if (info.isAdmin()) {
166-
if (!permission.isConfig()) {
167-
throw new DSPermissionException("Config permission required");
168-
}
169-
} else if (!info.isReadOnly()) {
170-
if (DSPermission.WRITE.isGreaterThan(permission)) {
171-
throw new DSPermissionException("Write permission required");
172-
}
173160
} else {
174-
if (DSPermission.READ.isGreaterThan(permission)) {
175-
throw new DSPermissionException("Read permission required");
161+
DSInfo info = path.getTargetInfo();
162+
if (!info.isAction()) {
163+
throw new DSRequestException("Not an action " + path.getPath());
164+
}
165+
if (info.isAdmin()) {
166+
if (!permission.isConfig()) {
167+
throw new DSPermissionException("Config permission required");
168+
}
169+
} else if (!info.isReadOnly()) {
170+
if (DSPermission.WRITE.isGreaterThan(permission)) {
171+
throw new DSPermissionException("Write permission required");
172+
}
173+
} else {
174+
if (DSPermission.READ.isGreaterThan(permission)) {
175+
throw new DSPermissionException("Read permission required");
176+
}
176177
}
178+
result = path.getNode().invoke(info, path.getParentInfo(), this);
177179
}
178-
path.getNode().invoke(info, path.getParentInfo(), this);
179180
} catch (Exception x) {
180181
error(getPath(), x);
181182
close(x);
Lines changed: 157 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,231 @@
11
package org.iot.dsa.dslink.requester;
22

3-
import org.iot.dsa.dslink.DSRequestException;
3+
import java.util.ArrayList;
44
import org.iot.dsa.node.DSList;
55
import org.iot.dsa.node.DSMap;
66

77
/**
88
* Action handler for non-tables/streams.
99
* <p>
10-
* Call getResult(long timeout) to block until the invocation is complete. It will either return
10+
* Call getUpdate(long timeout) to block until the invocation is complete. It will either return
1111
* the result (possibly null), or throw an exception.
1212
*
1313
* @author Aaron Hansen
1414
*/
1515
public class SimpleInvokeHandler extends AbstractInvokeHandler {
1616

1717
///////////////////////////////////////////////////////////////////////////
18-
// Fields
18+
// Instance Fields
1919
///////////////////////////////////////////////////////////////////////////
2020

21-
private boolean autoClose = true;
2221
private boolean closed = false;
22+
private DSList columns;
2323
private RuntimeException error;
24-
private DSList result;
24+
private Mode mode;
25+
private DSMap tableMeta;
26+
private ArrayList<DSList> updates;
2527

2628
///////////////////////////////////////////////////////////////////////////
27-
// Methods
29+
// Public Methods
2830
///////////////////////////////////////////////////////////////////////////
2931

3032
/**
31-
* Waits for the stream to close before returning, or the timeout to occur.
33+
* It is possible for a values action to not return columns.
3234
*
33-
* @param timeout Passed to Object.wait
34-
* @return Null, or the first update.
35+
* @return Beware of null.
36+
*/
37+
public int getColumnCount() {
38+
if (columns == null) {
39+
return 0;
40+
}
41+
return columns.size();
42+
}
43+
44+
/**
45+
* The metadata map for the given column.
46+
*/
47+
public DSMap getColumnMetadata(int idx) {
48+
return columns.getMap(idx);
49+
}
50+
51+
public RuntimeException getError() {
52+
return error;
53+
}
54+
55+
public Mode getMode() {
56+
return mode;
57+
}
58+
59+
public DSMap getTableMeta() {
60+
return tableMeta;
61+
}
62+
63+
/**
64+
* The next available update, or null for actions return void.
65+
* Will wait for an update if one isn't available. Will return all updates before
66+
* throwing any exceptions.
67+
*
68+
* @param timeout How long to wait for an update or the stream to close.
69+
* @return Null if the action doesn't return anything.
3570
* @throws RuntimeException if there is a timeout, or if there are any errors.
3671
*/
37-
public DSList getResult(long timeout) {
72+
public DSList getUpdate(long timeout) {
73+
long end = System.currentTimeMillis() + timeout;
3874
synchronized (this) {
39-
if (!closed) {
75+
while (!closed && !hasError() && !hasUpdates()) {
4076
try {
4177
wait(timeout);
42-
} catch (Exception x) {
78+
} catch (Exception expected) {
79+
}
80+
if (System.currentTimeMillis() > end) {
81+
break;
4382
}
4483
}
45-
}
46-
if (error != null) {
47-
throw error;
48-
}
49-
if (!closed) {
84+
if (hasUpdates()) {
85+
return updates.remove(0);
86+
}
87+
if (hasError()) {
88+
throw error;
89+
}
90+
if (closed) {
91+
return null;
92+
}
5093
throw new IllegalStateException("Action timed out");
5194
}
52-
return result;
5395
}
5496

5597
/**
56-
* True by default, whether or not to close the stream upon receiving the first result.
98+
* Takes the updates such that subsequent calls will never return the same updates, except when
99+
* there are no updates in which case this returns null.
100+
*
101+
* @return Possibly null.
57102
*/
58-
public boolean isAutoClose() {
59-
return autoClose;
103+
public synchronized ArrayList<DSList> getUpdates() {
104+
ArrayList<DSList> ret = updates;
105+
updates = null;
106+
return ret;
60107
}
61108

62-
/**
63-
* Causes getResult to return.
64-
*/
65-
public void onClose() {
66-
synchronized (this) {
67-
closed = true;
68-
notifyAll();
69-
}
109+
public boolean hasError() {
110+
return error != null;
70111
}
71112

72-
/**
73-
* Will create an exception to be thrown by getResult.
74-
*/
75-
public void onError(ErrorType type, String msg) {
76-
synchronized (this) {
77-
error = ErrorType.makeException(type, msg);
78-
getStream().closeStream();
79-
notifyAll();
113+
public synchronized boolean hasUpdates() {
114+
if (updates == null) {
115+
return false;
80116
}
117+
return !updates.isEmpty();
81118
}
82119

83-
/**
84-
* Does nothing.
85-
*/
86-
public void onColumns(DSList list) {
120+
public boolean isClosed() {
121+
return closed;
122+
}
123+
124+
@Override
125+
public synchronized void onClose() {
126+
closed = true;
127+
notifyAll();
128+
}
129+
130+
@Override
131+
public synchronized void onColumns(DSList list) {
132+
this.columns = list;
133+
notifyAll();
87134
}
88135

89136
/**
90-
* Will result in an error since tables and streams are not supported.
137+
* Creates an exception that will be thrown by getUpdate.
91138
*/
92-
public void onInsert(int index, DSList rows) {
93-
synchronized (this) {
94-
error = new DSRequestException("Tables and streams not supported");
95-
getStream().closeStream();
96-
notifyAll();
97-
}
139+
@Override
140+
public synchronized void onError(ErrorType type, String msg) {
141+
error = ErrorType.makeException(type, msg);
142+
notifyAll();
98143
}
99144

100145
/**
101-
* Does nothing.
146+
* Does nothing other than notify and threads waiting on this instance.
102147
*/
103-
public void onMode(Mode mode) {
148+
@Override
149+
public synchronized void onInsert(int index, DSList rows) {
150+
notifyAll();
151+
}
152+
153+
@Override
154+
public synchronized void onMode(Mode mode) {
155+
this.mode = mode;
156+
notifyAll();
104157
}
105158

106159
/**
107-
* Will result in an error since tables and streams are not supported.
160+
* Does nothing other than notify and threads waiting on this instance.
108161
*/
109-
public void onReplace(int start, int end, DSList rows) {
110-
synchronized (this) {
111-
error = new DSRequestException("Tables and streams not supported");
112-
getStream().closeStream();
113-
notifyAll();
114-
}
162+
@Override
163+
public synchronized void onReplace(int start, int end, DSList rows) {
164+
notifyAll();
115165
}
116166

117-
public void onTableMeta(DSMap map) {
167+
@Override
168+
public synchronized void onTableMeta(DSMap map) {
169+
this.tableMeta = map;
170+
notifyAll();
118171
}
119172

120173
/**
121174
* Captures the result and if auto-close is true, closes the stream.
122175
*/
123-
public void onUpdate(DSList row) {
176+
@Override
177+
public synchronized void onUpdate(DSList row) {
178+
if (updates == null) {
179+
updates = new ArrayList<>();
180+
}
181+
updates.add(row);
182+
notifyAll();
183+
}
184+
185+
/**
186+
* Waits for any callback from the responder. Will return immediately if already closed.
187+
*
188+
* @param timeout Passed to Object.wait
189+
* @throws RuntimeException if there is an error with the invocation.
190+
* @throws IllegalStateException if there is a timeout, or if there are any errors.
191+
*/
192+
public void waitForCallback(long timeout) {
124193
synchronized (this) {
125-
result = row;
126-
if (autoClose) {
127-
getStream().closeStream();
194+
if (!closed) {
195+
long end = System.currentTimeMillis() + timeout;
196+
try {
197+
wait(timeout);
198+
} catch (Exception x) {
199+
}
200+
if (System.currentTimeMillis() > end) {
201+
throw new IllegalStateException("Action timed out");
202+
}
128203
}
129204
}
130205
}
131206

132207
/**
133-
* Whether or not to auto close the stream on the first update. True by default, this
134-
* only needs to be called to disable.
208+
* Waits for the stream to close or the timeout to occur.
209+
*
210+
* @param timeout Passed to Object.wait
211+
* @throws IllegalStateException if there is a timeout, or if there are any errors.
135212
*/
136-
public SimpleInvokeHandler setAutoClose(boolean arg) {
137-
autoClose = arg;
138-
return this;
213+
public void waitForClose(long timeout) {
214+
long end = System.currentTimeMillis() + timeout;
215+
synchronized (this) {
216+
while (!closed) {
217+
try {
218+
wait(timeout);
219+
} catch (Exception x) {
220+
}
221+
if (System.currentTimeMillis() > end) {
222+
break;
223+
}
224+
}
225+
}
226+
if (!closed) {
227+
throw new IllegalStateException("Action timed out");
228+
}
139229
}
140230

141231
}

0 commit comments

Comments
 (0)