Skip to content

Commit 3d6a892

Browse files
committed
Adding readOnce
1 parent f801496 commit 3d6a892

3 files changed

Lines changed: 120 additions & 0 deletions

File tree

gpclient/gpclient-core/src/main/java/org/epics/gpclient/GPClient.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.time.Duration;
88
import java.util.List;
99
import java.util.concurrent.Executors;
10+
import java.util.concurrent.Future;
1011
import org.epics.gpclient.datasource.DataSourceProvider;
1112
import org.epics.vtype.VType;
1213

@@ -27,6 +28,27 @@ public class GPClient {
2728

2829
private static final GPClientInstance gpClient;
2930

31+
/**
32+
* Reads the value of the given expression, asking for {@link VType} values.
33+
*
34+
* @param channelName the name of the channel
35+
* @return the future value
36+
*/
37+
public static Future<VType> readOnce(String channelName) {
38+
return gpClient.readOnce(channelName);
39+
}
40+
41+
/**
42+
* Reads the value of the given expression.
43+
*
44+
* @param <R> the read type
45+
* @param expression the expression to read
46+
* @return the future value
47+
*/
48+
public static <R> Future<R> readOnce(Expression<R, ?> expression) {
49+
return gpClient.readOnce(expression);
50+
}
51+
3052
/**
3153
* Reads the channel with the given name, asking for {@link VType} values.
3254
*

gpclient/gpclient-core/src/main/java/org/epics/gpclient/GPClientInstance.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55
package org.epics.gpclient;
66

77
import java.time.Duration;
8+
import java.util.concurrent.CountDownLatch;
9+
import java.util.concurrent.ExecutionException;
810
import java.util.concurrent.Executor;
11+
import java.util.concurrent.Future;
912
import java.util.concurrent.ScheduledExecutorService;
13+
import java.util.concurrent.TimeUnit;
14+
import java.util.concurrent.TimeoutException;
15+
import java.util.concurrent.atomic.AtomicReference;
16+
import java.util.function.Consumer;
1017
import org.epics.gpclient.datasource.DataSource;
1118
import org.epics.vtype.VType;
1219
import static org.epics.gpclient.GPClient.*;
@@ -31,6 +38,85 @@ public class GPClientInstance {
3138
this.defaultNotificationExecutor = config.defaultNotificationExecutor;
3239
}
3340

41+
/**
42+
* Reads the value of the given expression, asking for {@link VType} values.
43+
*
44+
* @param channelName the name of the channel
45+
* @return the future value
46+
*/
47+
public Future<VType> readOnce(String channelName) {
48+
return readOnce(channel(channelName));
49+
}
50+
51+
/**
52+
* Reads the value of the given expression.
53+
*
54+
* @param <R> the read type
55+
* @param expression the expression to read
56+
* @return the future value
57+
*/
58+
public <R> Future<R> readOnce(Expression<R, ?> expression) {
59+
final AtomicReference<R> result = new AtomicReference<>();
60+
final AtomicReference<Exception> error = new AtomicReference<>();
61+
final CountDownLatch latch = new CountDownLatch(1);
62+
final PVReader<R> pvReader = read(expression).addReadListener((event, pv) -> {
63+
if (event.isType(PVEvent.Type.VALUE)) {
64+
result.set(pv.getValue());
65+
pv.close();
66+
latch.countDown();
67+
}
68+
if (event.isType(PVEvent.Type.EXCEPTION)) {
69+
error.set(event.getException());
70+
pv.close();
71+
latch.countDown();
72+
}
73+
}).start();
74+
Future<R> future = new Future<R>() {
75+
@Override
76+
public boolean cancel(boolean mayInterruptIfRunning) {
77+
boolean toCancel = !pvReader.isClosed();
78+
if (toCancel) {
79+
pvReader.close();
80+
}
81+
return toCancel;
82+
}
83+
84+
@Override
85+
public boolean isCancelled() {
86+
return pvReader.isClosed() && result.get() == null;
87+
}
88+
89+
@Override
90+
public boolean isDone() {
91+
return pvReader.isClosed() && result.get() != null;
92+
}
93+
94+
@Override
95+
public R get() throws InterruptedException, ExecutionException {
96+
latch.await();
97+
return getResult();
98+
}
99+
100+
private R getResult() throws ExecutionException {
101+
if (error.get() != null) {
102+
throw new ExecutionException(error.get());
103+
} else {
104+
return result.get();
105+
}
106+
}
107+
108+
@Override
109+
public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
110+
if (latch.await(timeout, unit)) {
111+
return getResult();
112+
} else {
113+
throw new TimeoutException();
114+
}
115+
}
116+
};
117+
return future;
118+
}
119+
34120
/**
35121
* Reads the channel with the given name, asking for {@link VType} values.
36122
*

gpclient/gpclient-sample/src/main/java/org/epics/gpclient/sample/BasicExamples.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.time.Duration;
88
import java.util.List;
9+
import java.util.concurrent.Future;
910
import java.util.logging.Level;
1011
import java.util.logging.Logger;
1112
import org.epics.gpclient.GPClient;
@@ -20,6 +21,16 @@
2021
*/
2122
public class BasicExamples {
2223

24+
public static void simpleReadOnce() {
25+
Future<VType> value = GPClient.readOnce("sim://noise");
26+
27+
try {
28+
System.out.println("Value " + value.get());
29+
} catch (Exception ex) {
30+
Logger.getLogger(BasicExamples.class.getName()).log(Level.SEVERE, null, ex);
31+
}
32+
}
33+
2334
public static void simpleRead() {
2435
PVReader<VType> pv = GPClient.read("sim://noise")
2536
.addReadListener((event, p) -> {
@@ -115,6 +126,7 @@ public static void pause(int millis) {
115126
}
116127

117128
public static void main(String[] args) {
129+
run("Simple read once", BasicExamples::simpleReadOnce);
118130
run("Simple read", BasicExamples::simpleRead);
119131
run("Simple read and write", BasicExamples::simpleReadAndWrite);
120132
run("Connection timeout", BasicExamples::connectionTimeout);

0 commit comments

Comments
 (0)