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

leeonky / test-charm-java / 212

14 Apr 2025 05:15AM UTC coverage: 74.088% (-0.1%) from 74.209%
212

push

circleci

leeonky
Update version

7957 of 10740 relevant lines covered (74.09%)

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.util.function.Extension.getFirstPresent;
28
import static java.lang.Long.parseLong;
29
import static java.util.Objects.requireNonNull;
30
import static java.util.Optional.ofNullable;
31

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

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

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

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

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

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

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

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

105
    private static int getServerPort() {
106

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

249

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

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

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

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

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

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

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

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

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

315
            return dalInstance.hold();
1✔
316

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

418
    interface Watch {
419
        Map<String, Object> collect();
420
    }
421
}
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