• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

leeonky / test-charm-java / 209

09 Apr 2025 07:49AM UTC coverage: 74.209% (+0.07%) from 74.136%
209

push

circleci

leeonky
Support meta property pattern

15 of 15 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

8019 of 10806 relevant lines covered (74.21%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.77
/DAL-extension-inspector/src/main/java/com/github/leeonky/dal/extensions/inspector/Inspector.java
1
package com.github.leeonky.dal.extensions.inspector;
2

3
import com.github.leeonky.dal.DAL;
4
import com.github.leeonky.dal.ast.node.DALNode;
5
import com.github.leeonky.dal.runtime.Data;
6
import com.github.leeonky.dal.runtime.RuntimeContextBuilder.DALRuntimeContext;
7
import com.github.leeonky.interpreter.InterpreterException;
8
import com.github.leeonky.util.Sneaky;
9
import io.javalin.Javalin;
10
import io.javalin.http.Context;
11
import io.javalin.http.staticfiles.Location;
12
import io.javalin.websocket.WsContext;
13
import org.apache.tika.Tika;
14

15
import java.io.ByteArrayOutputStream;
16
import java.io.InputStream;
17
import java.net.InetAddress;
18
import java.net.NetworkInterface;
19
import java.time.Duration;
20
import java.time.Instant;
21
import java.util.*;
22
import java.util.concurrent.ConcurrentHashMap;
23
import java.util.concurrent.CountDownLatch;
24
import java.util.function.Supplier;
25
import java.util.stream.Collectors;
26

27
import static com.github.leeonky.dal.runtime.Data.ResolvedMethods.cast;
28
import static com.github.leeonky.util.function.Extension.getFirstPresent;
29
import static java.lang.Long.parseLong;
30
import static java.util.Objects.requireNonNull;
31
import static java.util.Optional.ofNullable;
32

33
public class Inspector {
34
    private static Inspector inspector = null;
1✔
35
    private static Mode mode = null;
1✔
36
    private final Javalin javalin;
37
    private final CountDownLatch serverReadyLatch = new CountDownLatch(1);
1✔
38
    private final Set<DAL> instances = new LinkedHashSet<>();
1✔
39
    //   TODO refactor
40
    private final Map<String, WsContext> clientConnections = new ConcurrentHashMap<>();
1✔
41
    private final Map<String, Set<String>> clientMonitors = new ConcurrentHashMap<>();
1✔
42
    private final Map<String, DalInstance> dalInstances = new ConcurrentHashMap<>();
1✔
43
    private static Supplier<Object> defaultInput = () -> null;
1✔
44

45
    public Inspector() {
1✔
46
        DalInstance defaultInstance = new DalInstance(() -> defaultInput.get(), DAL.create("Try It!", InspectorExtension.class), "");
1✔
47
        defaultInstance.running = false;
1✔
48
        dalInstances.put("Try It!", defaultInstance);
1✔
49
        javalin = Javalin.create(config -> config.addStaticFiles("/public", Location.CLASSPATH))
1✔
50
                .events(event -> event.serverStarted(serverReadyLatch::countDown));
1✔
51
        requireNonNull(javalin.jettyServer()).setServerPort(getServerPort());
1✔
52
        javalin.get("/", ctx -> ctx.redirect("/index.html"));
1✔
53
        javalin.post("/api/execute", ctx -> ctx.html(execute(ctx.queryParam("name"), ctx.body())));
1✔
54
        javalin.post("/api/exchange", ctx -> exchange(ctx.queryParam("session"), ctx.body()));
1✔
55
        javalin.post("/api/pass", ctx -> pass(ctx.queryParam("name")));
1✔
56
        javalin.post("/api/release", ctx -> release(ctx.queryParam("name")));
1✔
57
        javalin.post("/api/release-all", ctx -> releaseAll());
1✔
58
        javalin.get("/api/request", ctx -> ctx.html(request(ctx.queryParam("name"))));
1✔
59
        javalin.get("/attachments", ctx -> responseAttachment(ctx.queryParam("name"), Integer.parseInt(ctx.queryParam("index")), ctx));
1✔
60
        javalin.ws("/ws/exchange", ws -> {
1✔
61
            ws.onConnect(ctx -> {
1✔
62
                clientConnections.put(ctx.getSessionId(), ctx);
1✔
63
                sendInstances(ctx);
1✔
64
            });
1✔
65
            ws.onClose(ctx -> clientConnections.remove(ctx.getSessionId()));
1✔
66
        });
1✔
67
        javalin.start();
1✔
68
    }
1✔
69

70
    private void responseAttachment(String name, int index, Context ctx) {
71
        DalInstance dalInstance = dalInstances.get(name);
1✔
72
        if (dalInstance != null) {
1✔
73
            Watch watch = dalInstance.watches.get(index);
1✔
74
            if (watch instanceof DalInstance.BinaryWatch) {
1✔
75

76
                DalInstance.BinaryWatch binaryWatch = (DalInstance.BinaryWatch) watch;
1✔
77
                String contentType = Sneaky.get(() -> new Tika().detect(binaryWatch.binary()));
1✔
78
                ctx.contentType(contentType == null ? "application/octet-stream" : contentType);
1✔
79
                ctx.result(binaryWatch.binary());
1✔
80
            }
81
        }
82
    }
1✔
83

84
    public static void watch(DAL dal, String property, Data value) {
85
        if (inspector != null)
1✔
86
            inspector.watchInner(dal, property, value);
1✔
87
    }
1✔
88

89
    private void watchInner(DAL dal, String property, Data value) {
90
        if (inspector.calledFromInspector())
1✔
91
            dalInstances.get(dal.getName()).watch(property, value);
1✔
92
    }
1✔
93

94
    private void pass(String name) {
95
        if (!name.equals("Try It!")) {
1✔
96
            DalInstance remove = dalInstances.remove(name);
1✔
97
            if (remove != null)
1✔
98
                remove.pass();
1✔
99
        }
100
    }
1✔
101

102
    private void waitForReady() {
103
        Sneaky.run(serverReadyLatch::await);
1✔
104
    }
1✔
105

106
    private static int getServerPort() {
107

108
        return getFirstPresent(() -> ofNullable(System.getenv("DAL_INSPECTOR_PORT")),
1✔
109
                () -> ofNullable(System.getProperty("dal.inspector.port")))
1✔
110
                .map(Integer::parseInt)
1✔
111
                .orElse(10082);
1✔
112
    }
113

114
    public static void ready() {
115
        inspector.waitForReady();
1✔
116
    }
1✔
117

118
    private void releaseAll() {
119
        for (String instanceName : new ArrayList<>(dalInstances.keySet()))
1✔
120
            release(instanceName);
1✔
121
    }
1✔
122

123
    private void release(String name) {
124
        if (!name.equals("Try It!")) {
1✔
125
            DalInstance remove = dalInstances.remove(name);
1✔
126
            if (remove != null)
1✔
127
                remove.release();
1✔
128
        }
129
    }
1✔
130

131
    public static void setDefaultMode(Mode mode) {
132
        Inspector.mode = mode;
1✔
133
    }
1✔
134

135
    private void exchange(String session, String body) {
136
        if (clientConnections.containsKey(session)) {
1✔
137
            clientMonitors.put(session, Arrays.stream(body.trim().split("\\n")).map(String::trim).filter(s -> !s.isEmpty()).collect(Collectors.toSet()));
1✔
138

139
            for (DalInstance dalInstance : dalInstances.values()) {
1✔
140
                if (dalInstance.running)
1✔
141
                    clientConnections.get(session).send(ObjectWriter.serialize(new HashMap<String, String>() {{
1✔
142
                        put("request", dalInstance.dal.getName());
1✔
143
                    }}));
1✔
144
            }
1✔
145
        }
146
    }
1✔
147

148
    public static class DalInstance {
149
        private final Supplier<Object> input;
150
        private boolean running = true;
1✔
151
        private boolean pass = false;
1✔
152
        private final DAL dal;
153
        private final String code;
154
        private final List<Watch> watches = new ArrayList<>();
1✔
155
        private final Data inputData;
156

157
        public DalInstance(Supplier<Object> input, DAL dal, String code) {
1✔
158
            this.input = input;
1✔
159
            this.dal = dal;
1✔
160
            this.code = code;
1✔
161
            inputData = null;
1✔
162
        }
1✔
163

164
        public DalInstance(Data inputData, DAL dal, String code) {
1✔
165
            input = inputData::instance;
1✔
166
            this.inputData = inputData;
1✔
167
            this.dal = dal;
1✔
168
            this.code = code;
1✔
169
        }
1✔
170

171
        public String execute(String code) {
172
            watches.clear();
1✔
173
            Map<String, Object> response = new HashMap<>();
1✔
174
            DALRuntimeContext runtimeContext = dal.getRuntimeContextBuilder().build(input::get, null);
1✔
175
            try {
176
                response.put("root", runtimeContext.data(input::get, null).dump());
1✔
177
                DALNode dalNode = dal.compileSingle(code, runtimeContext);
1✔
178
                response.put("inspect", dalNode.inspect());
1✔
179
                response.put("result", dalNode.evaluateData(runtimeContext).resolve().dump());
1✔
180
            } catch (InterpreterException e) {
1✔
181
                response.put("error", e.show(code) + "\n\n" + e.getMessage());
1✔
182
            }
1✔
183
            response.put("watches", watches.stream().map(Watch::collect).collect(Collectors.toList()));
1✔
184
            return ObjectWriter.serialize(response);
1✔
185
        }
186

187
        public boolean hold() {
188
            System.err.println("Waiting for DAL inspector release...");
1✔
189
            try {
190
                Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
1✔
191

192
                System.err.println("\tDal inspector running at:");
1✔
193

194
                while (interfaces.hasMoreElements()) {
1✔
195
                    Enumeration<InetAddress> inetAddresses = interfaces.nextElement().getInetAddresses();
1✔
196
                    while (inetAddresses.hasMoreElements()) {
1✔
197
                        InetAddress address = inetAddresses.nextElement();
1✔
198
                        System.err.printf("\t\thttp://%s:%d%n", address.getHostAddress(), getServerPort());
1✔
199
                    }
1✔
200
                }
1✔
201
            } catch (Exception ignore) {
×
202
            }
1✔
203
            //        TODO use sempahore to wait for the result
204
            Instant now = Instant.now();
1✔
205
            while (running && stillWaiting(now))
1✔
206
                Sneaky.run(() -> Thread.sleep(20));
1✔
207
//            TODO use logger
208
            System.err.println("DAL inspector released with pass: " + pass);
1✔
209
            return pass;
1✔
210
        }
211

212
        public void release() {
213
            running = false;
1✔
214
        }
1✔
215

216
        public void pass() {
217
            pass = true;
1✔
218
            release();
1✔
219
        }
1✔
220

221
        private byte[] getBytes(Data data) {
222
            return getFirstPresent(
1✔
223
                    () -> data.probe(cast(byte[].class)),
1✔
224
                    () -> data.probe(cast(InputStream.class)).map(stream -> Sneaky.get(() -> {
1✔
225
                        try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
×
226
                            int size;
227
                            byte[] data1 = new byte[1024];
×
228
                            while ((size = stream.read(data1, 0, data1.length)) != -1)
×
229
                                buffer.write(data1, 0, size);
×
230
                            return buffer.toByteArray();
×
231
                        }
232
                    })),
233
                    () -> data.probe(cast(Byte[].class)).map(bytes -> {
1✔
234
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();
×
235
                        for (Byte b : bytes)
×
236
                            stream.write(b);
×
237
                        return stream.toByteArray();
×
238
                    })
239
            ).orElse(null);
1✔
240
        }
241

242
        public void watch(String property, Data value) {
243
            byte[] bytes = getBytes(value);
1✔
244
            if (bytes != null) {
1✔
245
                watches.add(new BinaryWatch(property, bytes));
1✔
246
            } else
247
                watches.add(new DefaultWatch(property, value));
1✔
248
        }
1✔
249

250

251
        public class DefaultWatch implements Watch {
252
            private final String property;
253
            private final String value;
254

255
            public DefaultWatch(String property, Data value) {
1✔
256
                this.property = property;
1✔
257
                this.value = value.dump();
1✔
258
            }
1✔
259

260
            @Override
261
            public Map<String, Object> collect() {
262
                return new HashMap<String, Object>() {{
1✔
263
                    put("property", property);
1✔
264
                    put("type", "DEFAULT");
1✔
265
                    put("value", value);
1✔
266
                }};
1✔
267
            }
268
        }
269

270
        private class BinaryWatch implements Watch {
271
            private final String property;
272
            private final int index;
273
            private final byte[] binary;
274

275
            public BinaryWatch(String property, byte[] value) {
1✔
276
                this.property = property;
1✔
277
                index = watches.size();
1✔
278
                binary = new byte[value.length];
1✔
279
                System.arraycopy(value, 0, binary, 0, value.length);
1✔
280
            }
1✔
281

282
            public byte[] binary() {
283
                return binary;
1✔
284
            }
285

286
            @Override
287
            public Map<String, Object> collect() {
288
                return new HashMap<String, Object>() {{
1✔
289
                    put("property", property);
1✔
290
                    put("type", "BINARY");
1✔
291
                    put("url", "/attachments?name=" + dal.getName() + "&index=" + index + "&tm=" + Instant.now().getEpochSecond());
1✔
292
                }};
1✔
293
            }
294
        }
295
    }
296

297
    public boolean inspectInner(DAL dal, Data input, String code) {
298
        if (calledFromInspector())
1✔
299
            return false;
×
300
//        lock inspect by name
301
//        check mode
302
        if (currentMode() == Mode.FORCED) {
1✔
303
            DalInstance dalInstance = new DalInstance(input, dal, code);
1✔
304
            dalInstances.put(dal.getName(), dalInstance);
1✔
305

306
//            List<WsContext> monitored = clientMonitors.entrySet().stream().filter(e -> e.getValue().contains(dal.getName()))
307
//                    .map(o -> clientConnections.get(o.getKey()))
308
//                    .collect(Collectors.toList());
309
//            TODO check monitor flag
310
            for (WsContext wsContext : clientConnections.values()) {
1✔
311
                wsContext.send(ObjectWriter.serialize(new HashMap<String, String>() {{
1✔
312
                    put("request", dal.getName());
1✔
313
                }}));
1✔
314
            }
1✔
315

316
            return dalInstance.hold();
1✔
317

318
        } else {
319
//        TODO refactor
320
            List<WsContext> monitored = clientMonitors.entrySet().stream().filter(e -> e.getValue().contains(dal.getName()))
1✔
321
                    .map(o -> clientConnections.get(o.getKey()))
1✔
322
                    .collect(Collectors.toList());
1✔
323
            if (!monitored.isEmpty()) {
1✔
324
                DalInstance dalInstance = new DalInstance(input, dal, code);
1✔
325
                dalInstances.put(dal.getName(), dalInstance);
1✔
326
                for (WsContext wsContext : monitored) {
1✔
327
                    wsContext.send(ObjectWriter.serialize(new HashMap<String, String>() {{
1✔
328
                        put("request", dal.getName());
1✔
329
                    }}));
1✔
330
                }
1✔
UNCOV
331
                return dalInstance.hold();
×
332
            }
333
            return false;
1✔
334
        }
335
    }
336

337
    private static boolean stillWaiting(Instant now) {
338
        String waitingTime = System.getenv("DAL_INSPECTOR_WAITING_TIME");
1✔
339
        return (waitingTime == null ? 3600 * 1000 * 24 : parseLong(waitingTime))
1✔
340
                > Duration.between(now, Instant.now()).toMillis();
1✔
341
    }
342

343
    public static boolean inspect(DAL dal, Data input, String code) {
344
        if (currentMode() != Mode.DISABLED)
1✔
345
            return inspector.inspectInner(dal, input, code);
1✔
346
        return false;
×
347
    }
348

349
    private String request(String name) {
350
//       TODO reject other request
351
        return dalInstances.get(name).code;
1✔
352
    }
353

354
    private String execute(String name, String code) {
355
        return dalInstances.get(name).execute(code);
1✔
356
    }
357

358
    public static void register(DAL dal) {
359
        inspector.addInstance(dal);
1✔
360
    }
1✔
361

362
    private void addInstance(DAL dal) {
363
        instances.add(dal);
1✔
364
        for (WsContext ctx : clientConnections.values()) {
1✔
365
            sendInstances(ctx);
1✔
366
        }
1✔
367
    }
1✔
368

369
    private void sendInstances(WsContext ctx) {
370
        ctx.send(ObjectWriter.serialize(new HashMap<String, Object>() {{
1✔
371
            put("instances", instances.stream().map(DAL::getName).collect(Collectors.toSet()));
1✔
372
            put("session", ctx.getSessionId());
1✔
373
        }}));
1✔
374
    }
1✔
375

376
    private void stop() {
377
        javalin.close();
1✔
378
    }
1✔
379

380
    public static void launch() {
381
        if (inspector == null) {
1✔
382
            inspector = new Inspector();
1✔
383
        }
384
    }
1✔
385

386
    public static void shutdown() {
387
        if (inspector != null) {
1✔
388
            inspector.stop();
1✔
389
            inspector = null;
1✔
390
        }
391
    }
1✔
392

393
    public static void setDefaultInput(Supplier<Object> supplier) {
394
        defaultInput = supplier;
1✔
395
    }
1✔
396

397
    public static Mode currentMode() {
398
        return getFirstPresent(() -> ofNullable(mode),
1✔
399
                () -> ofNullable(System.getenv("DAL_INSPECTOR_MODE")).map(Mode::valueOf),
×
400
                () -> ofNullable(System.getProperty("dal.inspector.mode")).map(Mode::valueOf))
×
401
                .orElse(Mode.DISABLED);
1✔
402
    }
403

404
    public enum Mode {
1✔
405
        DISABLED, FORCED, AUTO
1✔
406
    }
407

408
    private boolean calledFromInspector() {
409
        for (StackTraceElement stack : Thread.currentThread().getStackTrace())
1✔
410
            if (DalInstance.class.getName().equals(stack.getClassName()))
1✔
411
                return true;
1✔
412
        return false;
1✔
413
    }
414

415
    public static void main(String[] args) {
416
        launch();
×
417
    }
×
418

419
    interface Watch {
420
        Map<String, Object> collect();
421
    }
422
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc