map) {
976 |
977 | map.get("foo", resGet -> {
978 | if (resGet.succeeded()) {
979 | // Successfully got the value
980 | Object val = resGet.result();
981 | } else {
982 | // Something went wrong!
983 | }
984 | });
985 |
986 | }
987 |
988 | public void example5(Vertx vertx, SharedData sd) {
989 | sd.getLock("mylock", res -> {
990 | if (res.succeeded()) {
991 | // Got the lock!
992 | Lock lock = res.result();
993 |
994 | // 5 seconds later we release the lock so someone else can get it
995 |
996 | vertx.setTimer(5000, tid -> lock.release());
997 |
998 | } else {
999 | // Something went wrong
1000 | }
1001 | });
1002 | }
1003 |
1004 | public void example6(SharedData sd) {
1005 | sd.getLockWithTimeout("mylock", 10000, res -> {
1006 | if (res.succeeded()) {
1007 | // Got the lock!
1008 | Lock lock = res.result();
1009 |
1010 | } else {
1011 | // Failed to get lock
1012 | }
1013 | });
1014 | }
1015 |
1016 | public void example7(SharedData sd) {
1017 | sd.getCounter("mycounter", res -> {
1018 | if (res.succeeded()) {
1019 | Counter counter = res.result();
1020 | } else {
1021 | // Something went wrong!
1022 | }
1023 | });
1024 | }
1025 |
1026 |
1027 |
1028 | }
1029 |
1030 | ----
1031 |
1032 | Once you have an instance you can retrieve the current count, atomically increment it, decrement and add a value to
1033 | it using the various methods.
1034 |
1035 | See the `link:../../apidocs/io/vertx/core/shareddata/Counter.html[API docs]` for more information.
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/asciidoc/clojure/streams.adoc:
--------------------------------------------------------------------------------
1 | == Streams
2 |
3 | There are several objects in Vert.x that allow items to be read from and written.
4 |
5 | In previous versions the streams.adoc package was manipulating `link:../../apidocs/io/vertx/core/buffer/Buffer.html[Buffer]`
6 | objects exclusively. From now, streams are not coupled to buffers anymore and they work with any kind of objects.
7 |
8 | In Vert.x, write calls return immediately, and writes are queued internally.
9 |
10 | It's not hard to see that if you write to an object faster than it can actually write the data to
11 | its underlying resource, then the write queue can grow unbounded - eventually resulting in
12 | memory exhaustion.
13 |
14 | To solve this problem a simple flow control (_back-pressure_) capability is provided by some objects in the Vert.x API.
15 |
16 | Any flow control aware object that can be _written-to_ implements `link:../../apidocs/io/vertx/core/streams/WriteStream.html[WriteStream]`,
17 | while any flow control object that can be _read-from_ is said to implement `link:../../apidocs/io/vertx/core/streams/ReadStream.html[ReadStream]`.
18 |
19 | Let's take an example where we want to read from a `ReadStream` then write the data to a `WriteStream`.
20 |
21 | A very simple example would be reading from a `link:../../apidocs/io/vertx/core/net/NetSocket.html[NetSocket]` then writing back to the
22 | same `NetSocket` - since `NetSocket` implements both `ReadStream` and `WriteStream`. Note that this works
23 | between any `ReadStream` and `WriteStream` compliant object, including HTTP requests, HTTP responses,
24 | async files I/O, WebSockets, etc.
25 |
26 | A naive way to do this would be to directly take the data that has been read and immediately write it
27 | to the `NetSocket`:
28 |
29 | [source,clojure]
30 | ----
31 | /*
32 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
33 | *
34 | * This program and the accompanying materials are made available under the
35 | * terms of the Eclipse Public License 2.0 which is available at
36 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
37 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
38 | *
39 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
40 | */
41 |
42 | package examples;
43 |
44 | import io.vertx.core.Handler;
45 | import io.vertx.core.Vertx;
46 | import io.vertx.core.buffer.Buffer;
47 | import io.vertx.core.net.NetServer;
48 | import io.vertx.core.net.NetServerOptions;
49 | import io.vertx.core.net.NetSocket;
50 | import io.vertx.core.streams.Pump;
51 |
52 | /**
53 | * @author Julien Viet
54 | */
55 | public class StreamsExamples {
56 |
57 | public void pump1(Vertx vertx) {
58 | NetServer server = vertx.createNetServer(
59 | new NetServerOptions().setPort(1234).setHost("localhost")
60 | );
61 | server.connectHandler(sock -> {
62 | sock.handler(buffer -> {
63 | // Write the data straight back
64 | sock.write(buffer);
65 | });
66 | }).listen();
67 | }
68 |
69 | public void pump2(Vertx vertx) {
70 | NetServer server = vertx.createNetServer(
71 | new NetServerOptions().setPort(1234).setHost("localhost")
72 | );
73 | server.connectHandler(sock -> {
74 | sock.handler(buffer -> {
75 | if (!sock.writeQueueFull()) {
76 | sock.write(buffer);
77 | }
78 | });
79 |
80 | }).listen();
81 | }
82 |
83 | public void pump3(Vertx vertx) {
84 | NetServer server = vertx.createNetServer(
85 | new NetServerOptions().setPort(1234).setHost("localhost")
86 | );
87 | server.connectHandler(sock -> {
88 | sock.handler(buffer -> {
89 | sock.write(buffer);
90 | if (sock.writeQueueFull()) {
91 | sock.pause();
92 | }
93 | });
94 | }).listen();
95 | }
96 |
97 | public void pump4(Vertx vertx) {
98 | NetServer server = vertx.createNetServer(
99 | new NetServerOptions().setPort(1234).setHost("localhost")
100 | );
101 | server.connectHandler(sock -> {
102 | sock.handler(buffer -> {
103 | sock.write(buffer);
104 | if (sock.writeQueueFull()) {
105 | sock.pause();
106 | sock.drainHandler(done -> {
107 | sock.resume();
108 | });
109 | }
110 | });
111 | }).listen();
112 | }
113 |
114 | public void pump5(Vertx vertx) {
115 | NetServer server = vertx.createNetServer(
116 | new NetServerOptions().setPort(1234).setHost("localhost")
117 | );
118 | server.connectHandler(sock -> {
119 | Pump.pump(sock, sock).start();
120 | }).listen();
121 | }
122 | }
123 |
124 | ----
125 |
126 | There is a problem with the example above: if data is read from the socket faster than it can be
127 | written back to the socket, it will build up in the write queue of the `NetSocket`, eventually
128 | running out of RAM. This might happen, for example if the client at the other end of the socket
129 | wasn't reading fast enough, effectively putting back-pressure on the connection.
130 |
131 | Since `NetSocket` implements `WriteStream`, we can check if the `WriteStream` is full before
132 | writing to it:
133 |
134 | [source,clojure]
135 | ----
136 | /*
137 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
138 | *
139 | * This program and the accompanying materials are made available under the
140 | * terms of the Eclipse Public License 2.0 which is available at
141 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
142 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
143 | *
144 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
145 | */
146 |
147 | package examples;
148 |
149 | import io.vertx.core.Handler;
150 | import io.vertx.core.Vertx;
151 | import io.vertx.core.buffer.Buffer;
152 | import io.vertx.core.net.NetServer;
153 | import io.vertx.core.net.NetServerOptions;
154 | import io.vertx.core.net.NetSocket;
155 | import io.vertx.core.streams.Pump;
156 |
157 | /**
158 | * @author Julien Viet
159 | */
160 | public class StreamsExamples {
161 |
162 | public void pump1(Vertx vertx) {
163 | NetServer server = vertx.createNetServer(
164 | new NetServerOptions().setPort(1234).setHost("localhost")
165 | );
166 | server.connectHandler(sock -> {
167 | sock.handler(buffer -> {
168 | // Write the data straight back
169 | sock.write(buffer);
170 | });
171 | }).listen();
172 | }
173 |
174 | public void pump2(Vertx vertx) {
175 | NetServer server = vertx.createNetServer(
176 | new NetServerOptions().setPort(1234).setHost("localhost")
177 | );
178 | server.connectHandler(sock -> {
179 | sock.handler(buffer -> {
180 | if (!sock.writeQueueFull()) {
181 | sock.write(buffer);
182 | }
183 | });
184 |
185 | }).listen();
186 | }
187 |
188 | public void pump3(Vertx vertx) {
189 | NetServer server = vertx.createNetServer(
190 | new NetServerOptions().setPort(1234).setHost("localhost")
191 | );
192 | server.connectHandler(sock -> {
193 | sock.handler(buffer -> {
194 | sock.write(buffer);
195 | if (sock.writeQueueFull()) {
196 | sock.pause();
197 | }
198 | });
199 | }).listen();
200 | }
201 |
202 | public void pump4(Vertx vertx) {
203 | NetServer server = vertx.createNetServer(
204 | new NetServerOptions().setPort(1234).setHost("localhost")
205 | );
206 | server.connectHandler(sock -> {
207 | sock.handler(buffer -> {
208 | sock.write(buffer);
209 | if (sock.writeQueueFull()) {
210 | sock.pause();
211 | sock.drainHandler(done -> {
212 | sock.resume();
213 | });
214 | }
215 | });
216 | }).listen();
217 | }
218 |
219 | public void pump5(Vertx vertx) {
220 | NetServer server = vertx.createNetServer(
221 | new NetServerOptions().setPort(1234).setHost("localhost")
222 | );
223 | server.connectHandler(sock -> {
224 | Pump.pump(sock, sock).start();
225 | }).listen();
226 | }
227 | }
228 |
229 | ----
230 |
231 | This example won't run out of RAM but we'll end up losing data if the write queue gets full. What we
232 | really want to do is pause the `NetSocket` when the write queue is full:
233 |
234 | [source,clojure]
235 | ----
236 | /*
237 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
238 | *
239 | * This program and the accompanying materials are made available under the
240 | * terms of the Eclipse Public License 2.0 which is available at
241 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
242 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
243 | *
244 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
245 | */
246 |
247 | package examples;
248 |
249 | import io.vertx.core.Handler;
250 | import io.vertx.core.Vertx;
251 | import io.vertx.core.buffer.Buffer;
252 | import io.vertx.core.net.NetServer;
253 | import io.vertx.core.net.NetServerOptions;
254 | import io.vertx.core.net.NetSocket;
255 | import io.vertx.core.streams.Pump;
256 |
257 | /**
258 | * @author Julien Viet
259 | */
260 | public class StreamsExamples {
261 |
262 | public void pump1(Vertx vertx) {
263 | NetServer server = vertx.createNetServer(
264 | new NetServerOptions().setPort(1234).setHost("localhost")
265 | );
266 | server.connectHandler(sock -> {
267 | sock.handler(buffer -> {
268 | // Write the data straight back
269 | sock.write(buffer);
270 | });
271 | }).listen();
272 | }
273 |
274 | public void pump2(Vertx vertx) {
275 | NetServer server = vertx.createNetServer(
276 | new NetServerOptions().setPort(1234).setHost("localhost")
277 | );
278 | server.connectHandler(sock -> {
279 | sock.handler(buffer -> {
280 | if (!sock.writeQueueFull()) {
281 | sock.write(buffer);
282 | }
283 | });
284 |
285 | }).listen();
286 | }
287 |
288 | public void pump3(Vertx vertx) {
289 | NetServer server = vertx.createNetServer(
290 | new NetServerOptions().setPort(1234).setHost("localhost")
291 | );
292 | server.connectHandler(sock -> {
293 | sock.handler(buffer -> {
294 | sock.write(buffer);
295 | if (sock.writeQueueFull()) {
296 | sock.pause();
297 | }
298 | });
299 | }).listen();
300 | }
301 |
302 | public void pump4(Vertx vertx) {
303 | NetServer server = vertx.createNetServer(
304 | new NetServerOptions().setPort(1234).setHost("localhost")
305 | );
306 | server.connectHandler(sock -> {
307 | sock.handler(buffer -> {
308 | sock.write(buffer);
309 | if (sock.writeQueueFull()) {
310 | sock.pause();
311 | sock.drainHandler(done -> {
312 | sock.resume();
313 | });
314 | }
315 | });
316 | }).listen();
317 | }
318 |
319 | public void pump5(Vertx vertx) {
320 | NetServer server = vertx.createNetServer(
321 | new NetServerOptions().setPort(1234).setHost("localhost")
322 | );
323 | server.connectHandler(sock -> {
324 | Pump.pump(sock, sock).start();
325 | }).listen();
326 | }
327 | }
328 |
329 | ----
330 |
331 | We're almost there, but not quite. The `NetSocket` now gets paused when the file is full, but we also need to unpause
332 | it when the write queue has processed its backlog:
333 |
334 | [source,clojure]
335 | ----
336 | /*
337 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
338 | *
339 | * This program and the accompanying materials are made available under the
340 | * terms of the Eclipse Public License 2.0 which is available at
341 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
342 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
343 | *
344 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
345 | */
346 |
347 | package examples;
348 |
349 | import io.vertx.core.Handler;
350 | import io.vertx.core.Vertx;
351 | import io.vertx.core.buffer.Buffer;
352 | import io.vertx.core.net.NetServer;
353 | import io.vertx.core.net.NetServerOptions;
354 | import io.vertx.core.net.NetSocket;
355 | import io.vertx.core.streams.Pump;
356 |
357 | /**
358 | * @author Julien Viet
359 | */
360 | public class StreamsExamples {
361 |
362 | public void pump1(Vertx vertx) {
363 | NetServer server = vertx.createNetServer(
364 | new NetServerOptions().setPort(1234).setHost("localhost")
365 | );
366 | server.connectHandler(sock -> {
367 | sock.handler(buffer -> {
368 | // Write the data straight back
369 | sock.write(buffer);
370 | });
371 | }).listen();
372 | }
373 |
374 | public void pump2(Vertx vertx) {
375 | NetServer server = vertx.createNetServer(
376 | new NetServerOptions().setPort(1234).setHost("localhost")
377 | );
378 | server.connectHandler(sock -> {
379 | sock.handler(buffer -> {
380 | if (!sock.writeQueueFull()) {
381 | sock.write(buffer);
382 | }
383 | });
384 |
385 | }).listen();
386 | }
387 |
388 | public void pump3(Vertx vertx) {
389 | NetServer server = vertx.createNetServer(
390 | new NetServerOptions().setPort(1234).setHost("localhost")
391 | );
392 | server.connectHandler(sock -> {
393 | sock.handler(buffer -> {
394 | sock.write(buffer);
395 | if (sock.writeQueueFull()) {
396 | sock.pause();
397 | }
398 | });
399 | }).listen();
400 | }
401 |
402 | public void pump4(Vertx vertx) {
403 | NetServer server = vertx.createNetServer(
404 | new NetServerOptions().setPort(1234).setHost("localhost")
405 | );
406 | server.connectHandler(sock -> {
407 | sock.handler(buffer -> {
408 | sock.write(buffer);
409 | if (sock.writeQueueFull()) {
410 | sock.pause();
411 | sock.drainHandler(done -> {
412 | sock.resume();
413 | });
414 | }
415 | });
416 | }).listen();
417 | }
418 |
419 | public void pump5(Vertx vertx) {
420 | NetServer server = vertx.createNetServer(
421 | new NetServerOptions().setPort(1234).setHost("localhost")
422 | );
423 | server.connectHandler(sock -> {
424 | Pump.pump(sock, sock).start();
425 | }).listen();
426 | }
427 | }
428 |
429 | ----
430 |
431 | And there we have it. The `link:../../apidocs/io/vertx/core/streams/WriteStream.html#drainHandler-io.vertx.core.Handler-[drainHandler]` event handler will
432 | get called when the write queue is ready to accept more data, this resumes the `NetSocket` that
433 | allows more data to be read.
434 |
435 | Wanting to do this is quite common while writing Vert.x applications, so we provide a helper class
436 | called `link:../../apidocs/io/vertx/core/streams/Pump.html[Pump]` that does all of this hard work for you.
437 | You just feed it the `ReadStream` plus the `WriteStream` then start it:
438 |
439 | [source,clojure]
440 | ----
441 | /*
442 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation
443 | *
444 | * This program and the accompanying materials are made available under the
445 | * terms of the Eclipse Public License 2.0 which is available at
446 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
447 | * which is available at https://www.apache.org/licenses/LICENSE-2.0.
448 | *
449 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
450 | */
451 |
452 | package examples;
453 |
454 | import io.vertx.core.Handler;
455 | import io.vertx.core.Vertx;
456 | import io.vertx.core.buffer.Buffer;
457 | import io.vertx.core.net.NetServer;
458 | import io.vertx.core.net.NetServerOptions;
459 | import io.vertx.core.net.NetSocket;
460 | import io.vertx.core.streams.Pump;
461 |
462 | /**
463 | * @author Julien Viet
464 | */
465 | public class StreamsExamples {
466 |
467 | public void pump1(Vertx vertx) {
468 | NetServer server = vertx.createNetServer(
469 | new NetServerOptions().setPort(1234).setHost("localhost")
470 | );
471 | server.connectHandler(sock -> {
472 | sock.handler(buffer -> {
473 | // Write the data straight back
474 | sock.write(buffer);
475 | });
476 | }).listen();
477 | }
478 |
479 | public void pump2(Vertx vertx) {
480 | NetServer server = vertx.createNetServer(
481 | new NetServerOptions().setPort(1234).setHost("localhost")
482 | );
483 | server.connectHandler(sock -> {
484 | sock.handler(buffer -> {
485 | if (!sock.writeQueueFull()) {
486 | sock.write(buffer);
487 | }
488 | });
489 |
490 | }).listen();
491 | }
492 |
493 | public void pump3(Vertx vertx) {
494 | NetServer server = vertx.createNetServer(
495 | new NetServerOptions().setPort(1234).setHost("localhost")
496 | );
497 | server.connectHandler(sock -> {
498 | sock.handler(buffer -> {
499 | sock.write(buffer);
500 | if (sock.writeQueueFull()) {
501 | sock.pause();
502 | }
503 | });
504 | }).listen();
505 | }
506 |
507 | public void pump4(Vertx vertx) {
508 | NetServer server = vertx.createNetServer(
509 | new NetServerOptions().setPort(1234).setHost("localhost")
510 | );
511 | server.connectHandler(sock -> {
512 | sock.handler(buffer -> {
513 | sock.write(buffer);
514 | if (sock.writeQueueFull()) {
515 | sock.pause();
516 | sock.drainHandler(done -> {
517 | sock.resume();
518 | });
519 | }
520 | });
521 | }).listen();
522 | }
523 |
524 | public void pump5(Vertx vertx) {
525 | NetServer server = vertx.createNetServer(
526 | new NetServerOptions().setPort(1234).setHost("localhost")
527 | );
528 | server.connectHandler(sock -> {
529 | Pump.pump(sock, sock).start();
530 | }).listen();
531 | }
532 | }
533 |
534 | ----
535 |
536 | This does exactly the same thing as the more verbose example.
537 |
538 | Let's now look at the methods on `ReadStream` and `WriteStream` in more detail:
539 |
540 | === ReadStream
541 |
542 | `ReadStream` is implemented by `link:../../apidocs/io/vertx/core/http/HttpClientResponse.html[HttpClientResponse]`, `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]`,
543 | `link:../../apidocs/io/vertx/core/http/HttpClientRequest.html[HttpClientRequest]`, `link:../../apidocs/io/vertx/core/http/HttpServerFileUpload.html[HttpServerFileUpload]`,
544 | `link:../../apidocs/io/vertx/core/http/HttpServerRequest.html[HttpServerRequest]`, `link:../../apidocs/io/vertx/core/eventbus/MessageConsumer.html[MessageConsumer]`,
545 | `link:../../apidocs/io/vertx/core/net/NetSocket.html[NetSocket]`, `link:../../apidocs/io/vertx/core/http/WebSocket.html[WebSocket]`, `link:../../apidocs/io/vertx/core/TimeoutStream.html[TimeoutStream]`,
546 | `link:../../apidocs/io/vertx/core/file/AsyncFile.html[AsyncFile]`.
547 |
548 | Functions:
549 |
550 | - `link:../../apidocs/io/vertx/core/streams/ReadStream.html#handler-io.vertx.core.Handler-[handler]`:
551 | set a handler which will receive items from the ReadStream.
552 | - `link:../../apidocs/io/vertx/core/streams/ReadStream.html#pause--[pause]`:
553 | pause the handler. When paused no items will be received in the handler.
554 | - `link:../../apidocs/io/vertx/core/streams/ReadStream.html#resume--[resume]`:
555 | resume the handler. The handler will be called if any item arrives.
556 | - `link:../../apidocs/io/vertx/core/streams/ReadStream.html#exceptionHandler-io.vertx.core.Handler-[exceptionHandler]`:
557 | Will be called if an exception occurs on the ReadStream.
558 | - `link:../../apidocs/io/vertx/core/streams/ReadStream.html#endHandler-io.vertx.core.Handler-[endHandler]`:
559 | Will be called when end of stream is reached. This might be when EOF is reached if the ReadStream represents a file,
560 | or when end of request is reached if it's an HTTP request, or when the connection is closed if it's a TCP socket.
561 |
562 | === WriteStream
563 |
564 | `WriteStream` is implemented by `link:../../apidocs/io/vertx/core/http/HttpClientRequest.html[HttpClientRequest]`, `link:../../apidocs/io/vertx/core/http/HttpServerResponse.html[HttpServerResponse]`
565 | `link:../../apidocs/io/vertx/core/http/WebSocket.html[WebSocket]`, `link:../../apidocs/io/vertx/core/net/NetSocket.html[NetSocket]`, `link:../../apidocs/io/vertx/core/file/AsyncFile.html[AsyncFile]`,
566 | and `link:../../apidocs/io/vertx/core/eventbus/MessageProducer.html[MessageProducer]`
567 |
568 | Functions:
569 |
570 | - `link:../../apidocs/io/vertx/core/streams/WriteStream.html#write-java.lang.Object-[write]`:
571 | write an object to the WriteStream. This method will never block. Writes are queued internally and asynchronously
572 | written to the underlying resource.
573 | - `link:../../apidocs/io/vertx/core/streams/WriteStream.html#setWriteQueueMaxSize-int-[setWriteQueueMaxSize]`:
574 | set the number of object at which the write queue is considered _full_, and the method `link:../../apidocs/io/vertx/core/streams/WriteStream.html#writeQueueFull--[writeQueueFull]`
575 | returns `true`. Note that, when the write queue is considered full, if write is called the data will still be accepted
576 | and queued. The actual number depends on the stream implementation, for `link:../../apidocs/io/vertx/core/buffer/Buffer.html[Buffer]` the size
577 | represents the actual number of bytes written and not the number of buffers.
578 | - `link:../../apidocs/io/vertx/core/streams/WriteStream.html#writeQueueFull--[writeQueueFull]`:
579 | returns `true` if the write queue is considered full.
580 | - `link:../../apidocs/io/vertx/core/streams/WriteStream.html#exceptionHandler-io.vertx.core.Handler-[exceptionHandler]`:
581 | Will be called if an exception occurs on the `WriteStream`.
582 | - `link:../../apidocs/io/vertx/core/streams/WriteStream.html#drainHandler-io.vertx.core.Handler-[drainHandler]`:
583 | The handler will be called if the `WriteStream` is considered no longer full.
584 |
585 | === Pump
586 |
587 | Instances of Pump have the following methods:
588 |
589 | - `link:../../apidocs/io/vertx/core/streams/Pump.html#start--[start]`:
590 | Start the pump.
591 | - `link:../../apidocs/io/vertx/core/streams/Pump.html#stop--[stop]`:
592 | Stops the pump. When the pump starts it is in stopped mode.
593 | - `link:../../apidocs/io/vertx/core/streams/Pump.html#setWriteQueueMaxSize-int-[setWriteQueueMaxSize]`:
594 | This has the same meaning as `link:../../apidocs/io/vertx/core/streams/WriteStream.html#setWriteQueueMaxSize-int-[setWriteQueueMaxSize]` on the `WriteStream`.
595 |
596 | A pump can be started and stopped multiple times.
597 |
598 | When a pump is first created it is _not_ started. You need to call the `start()` method to start it.
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/asciidoc/enums.adoc:
--------------------------------------------------------------------------------
1 | = Enums
2 |
3 | [[AllowForwardHeaders]]
4 | == AllowForwardHeaders
5 |
6 | ++++
7 | What kind of forward header parsing are we allowing.
8 | ++++
9 | '''
10 |
11 | [cols=">25%,75%"]
12 | [frame="topbot"]
13 | |===
14 | ^|Name | Description
15 | |[[NONE]]`NONE`|+++
16 | No parsing shall be performed.
17 | +++
18 | |[[FORWARD]]`FORWARD`|+++
19 | Only process the standard Forward
header as defined by https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded
22 | +++
23 | |[[X_FORWARD]]`X_FORWARD`|+++
24 | Only process the non standard but widely used X-Forward-*
headers.
25 |
26 | These headers are not official standards but widely used. Users are advised to avoid them for new applications.
27 | +++
28 | |[[ALL]]`ALL`|+++
29 | Will process both and . Be aware that mixing the 2 headers can open
30 | security holes has specially crafted requests that are not validated as proxy level can allow bypassing
31 | the proxy desired forward value.
32 |
33 | For example, a proxy will add the X-Forward-*
headers to a request but not filter out if the original
34 | request includes the Forward
header.
35 | +++
36 | |===
37 |
38 | [[Attestation]]
39 | == Attestation
40 |
41 |
42 | [cols=">25%,75%"]
43 | [frame="topbot"]
44 | |===
45 | ^|Name | Description
46 | |[[NONE]]`NONE`|-
47 | |[[DIRECT]]`DIRECT`|-
48 | |[[INDIRECT]]`INDIRECT`|-
49 | |===
50 |
51 | [[AuthenticatorAttachment]]
52 | == AuthenticatorAttachment
53 |
54 |
55 | [cols=">25%,75%"]
56 | [frame="topbot"]
57 | |===
58 | ^|Name | Description
59 | |[[CROSS_PLATFORM]]`CROSS_PLATFORM`|-
60 | |[[PLATFORM]]`PLATFORM`|-
61 | |===
62 |
63 | [[BridgeEventType]]
64 | == BridgeEventType
65 |
66 | ++++
67 | Bridge Event Types.
68 | ++++
69 | '''
70 |
71 | [cols=">25%,75%"]
72 | [frame="topbot"]
73 | |===
74 | ^|Name | Description
75 | |[[SOCKET_CREATED]]`SOCKET_CREATED`|+++
76 | This event will occur when a new SockJS socket is created.
77 | +++
78 | |[[SOCKET_CLOSED]]`SOCKET_CLOSED`|+++
79 | This event will occur when a SockJS socket is closed.
80 | +++
81 | |[[SOCKET_IDLE]]`SOCKET_IDLE`|+++
82 | This event will occur when SockJS socket is on idle for longer period of time than configured.
83 | +++
84 | |[[SOCKET_PING]]`SOCKET_PING`|+++
85 | This event will occur when the last ping timestamp is updated for the SockJS socket.
86 | +++
87 | |[[SEND]]`SEND`|+++
88 | This event will occur when a message is attempted to be sent from the client to the server.
89 | +++
90 | |[[PUBLISH]]`PUBLISH`|+++
91 | This event will occur when a message is attempted to be published from the client to the server.
92 | +++
93 | |[[RECEIVE]]`RECEIVE`|+++
94 | This event will occur when a message is attempted to be delivered from the server to the client.
95 | +++
96 | |[[REGISTER]]`REGISTER`|+++
97 | This event will occur when a client attempts to register a handler.
98 | +++
99 | |[[REGISTERED]]`REGISTERED`|+++
100 | This event will occur when a client successfully registered. The raw message used for registration, notified with event
101 | +++
102 | |[[UNREGISTER]]`UNREGISTER`|+++
103 | This event will occur when a client attempts to unregister a handler.
104 | +++
105 | |===
106 |
107 | [[ClientAuth]]
108 | == ClientAuth
109 |
110 | ++++
111 | Configures the engine to require/request client authentication.
112 |
113 | Created by manishk on 10/2/2015.
114 | ++++
115 | '''
116 |
117 | [cols=">25%,75%"]
118 | [frame="topbot"]
119 | |===
120 | ^|Name | Description
121 | |[[NONE]]`NONE`|+++
122 | No client authentication is requested or required.
123 | +++
124 | |[[REQUEST]]`REQUEST`|+++
125 | Accept authentication if presented by client. If this option is set and the client chooses
126 | not to provide authentication information about itself, the negotiations will continue.
127 | +++
128 | |[[REQUIRED]]`REQUIRED`|+++
129 | Require client to present authentication, if not presented then negotiations will be declined.
130 | +++
131 | |===
132 |
133 | [[CookieSameSite]]
134 | == CookieSameSite
135 |
136 | ++++
137 | Represents the Cookie SameSite policy to be used. For more info https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_cookies.
138 | ++++
139 | '''
140 |
141 | [cols=">25%,75%"]
142 | [frame="topbot"]
143 | |===
144 | ^|Name | Description
145 | |[[NONE]]`NONE`|+++
146 | The browser will send cookies with both cross-site requests and same-site requests.
147 | +++
148 | |[[STRICT]]`STRICT`|+++
149 | The browser will only send cookies for same-site requests (requests originating from the site that set the cookie).
150 | If the request originated from a different URL than the URL of the current location, none of the cookies tagged
151 | with the Strict attribute will be included.
152 | +++
153 | |[[LAX]]`LAX`|+++
154 | Same-site cookies are withheld on cross-site subrequests, such as calls to load images or frames, but will be sent
155 | when a user navigates to the URL from an external site; for example, by following a link.
156 | +++
157 | |===
158 |
159 | [[DnsResponseCode]]
160 | == DnsResponseCode
161 |
162 | ++++
163 | Represents the possible response codes a server may send after receiving a
164 | query. A response code of 0 indicates no error.
165 |
166 | ++++
167 | '''
168 |
169 | [cols=">25%,75%"]
170 | [frame="topbot"]
171 | |===
172 | ^|Name | Description
173 | |[[NOERROR]]`NOERROR`|+++
174 | ID 0, no error
175 | +++
176 | |[[FORMERROR]]`FORMERROR`|+++
177 | ID 1, format error
178 | +++
179 | |[[SERVFAIL]]`SERVFAIL`|+++
180 | ID 2, server failure
181 | +++
182 | |[[NXDOMAIN]]`NXDOMAIN`|+++
183 | ID 3, name error
184 | +++
185 | |[[NOTIMPL]]`NOTIMPL`|+++
186 | ID 4, not implemented
187 | +++
188 | |[[REFUSED]]`REFUSED`|+++
189 | ID 5, operation refused
190 | +++
191 | |[[YXDOMAIN]]`YXDOMAIN`|+++
192 | ID 6, domain name should not exist
193 | +++
194 | |[[YXRRSET]]`YXRRSET`|+++
195 | ID 7, resource record set should not exist
196 | +++
197 | |[[NXRRSET]]`NXRRSET`|+++
198 | ID 8, rrset does not exist
199 | +++
200 | |[[NOTAUTH]]`NOTAUTH`|+++
201 | ID 9, not authoritative for zone
202 | +++
203 | |[[NOTZONE]]`NOTZONE`|+++
204 | ID 10, name not in zone
205 | +++
206 | |[[BADVERS]]`BADVERS`|+++
207 | ID 11, bad extension mechanism for version
208 | +++
209 | |[[BADSIG]]`BADSIG`|+++
210 | ID 12, bad signature
211 | +++
212 | |[[BADKEY]]`BADKEY`|+++
213 | ID 13, bad key
214 | +++
215 | |[[BADTIME]]`BADTIME`|+++
216 | ID 14, bad timestamp
217 | +++
218 | |===
219 |
220 | [[FetchDirection]]
221 | == FetchDirection
222 |
223 | ++++
224 | Represents the fetch direction hint
225 | ++++
226 | '''
227 |
228 | [cols=">25%,75%"]
229 | [frame="topbot"]
230 | |===
231 | ^|Name | Description
232 | |[[FORWARD]]`FORWARD`|-
233 | |[[REVERSE]]`REVERSE`|-
234 | |[[UNKNOWN]]`UNKNOWN`|-
235 | |===
236 |
237 | [[HashAlgorithm]]
238 | == HashAlgorithm
239 |
240 |
241 | [cols=">25%,75%"]
242 | [frame="topbot"]
243 | |===
244 | ^|Name | Description
245 | |[[SHA512]]`SHA512`|+++
246 | The default algorithm for backward compatible systems.
247 |
248 | Should not be used for new projects as OWASP recommends stronger hashing algorithms.
249 | +++
250 | |[[PBKDF2]]`PBKDF2`|+++
251 | Stronger hashing algorithm, recommended by OWASP as of 2018.
252 | +++
253 | |===
254 |
255 | [[HashSaltStyle]]
256 | == HashSaltStyle
257 |
258 | ++++
259 | Password hash salt configuration.
260 | ++++
261 | '''
262 |
263 | [cols=">25%,75%"]
264 | [frame="topbot"]
265 | |===
266 | ^|Name | Description
267 | |[[NO_SALT]]`NO_SALT`|+++
268 | Password hashes are not salted
269 | +++
270 | |[[COLUMN]]`COLUMN`|+++
271 | Salt is in a separate column for each user in the database
272 | +++
273 | |[[EXTERNAL]]`EXTERNAL`|+++
274 | Salt is NOT stored in the database, but defined as external value like application preferences or so
275 | +++
276 | |===
277 |
278 | [[HttpVersion]]
279 | == HttpVersion
280 |
281 | ++++
282 | Represents the version of the HTTP protocol.
283 | ++++
284 | '''
285 |
286 | [cols=">25%,75%"]
287 | [frame="topbot"]
288 | |===
289 | ^|Name | Description
290 | |[[HTTP_1_0]]`HTTP_1_0`|-
291 | |[[HTTP_1_1]]`HTTP_1_1`|-
292 | |[[HTTP_2]]`HTTP_2`|-
293 | |===
294 |
295 | [[JsonEventType]]
296 | == JsonEventType
297 |
298 | ++++
299 | The possibles types of link emitted by the link.
300 | ++++
301 | '''
302 |
303 | [cols=">25%,75%"]
304 | [frame="topbot"]
305 | |===
306 | ^|Name | Description
307 | |[[START_OBJECT]]`START_OBJECT`|+++
308 | Signals the start of a JSON object.
309 | +++
310 | |[[END_OBJECT]]`END_OBJECT`|+++
311 | Signals the end of a JSON object.
312 | +++
313 | |[[START_ARRAY]]`START_ARRAY`|+++
314 | Signals the start of a JSON array.
315 | +++
316 | |[[END_ARRAY]]`END_ARRAY`|+++
317 | Signals the end of a JSON array.
318 | +++
319 | |[[VALUE]]`VALUE`|+++
320 | Signals a JSON value.
321 | +++
322 | |===
323 |
324 | [[LoggerFormat]]
325 | == LoggerFormat
326 |
327 | ++++
328 | The possible out of the box formats.
329 | ++++
330 | '''
331 |
332 | [cols=">25%,75%"]
333 | [frame="topbot"]
334 | |===
335 | ^|Name | Description
336 | |[[DEFAULT]]`DEFAULT`|+++
337 | remote-client - - [timestamp] "method uri version" status content-length "referrer" "user-agent"
338 | +++
339 | |[[SHORT]]`SHORT`|+++
340 | remote-client - method uri version status content-length duration ms
341 | +++
342 | |[[TINY]]`TINY`|+++
343 | method uri status - content-length duration
344 | +++
345 | |[[CUSTOM]]`CUSTOM`|+++
346 | Will use user defined formatter function.
347 | +++
348 | |===
349 |
350 | [[OAuth2FlowType]]
351 | == OAuth2FlowType
352 |
353 | ++++
354 | OAuth2 Flows
355 | ++++
356 | '''
357 |
358 | [cols=">25%,75%"]
359 | [frame="topbot"]
360 | |===
361 | ^|Name | Description
362 | |[[AUTH_CODE]]`AUTH_CODE`|+++
363 | The authorization code is obtained by using an authorization server
364 | as an intermediary between the client and resource owner. Instead of
365 | requesting authorization directly from the resource owner, the client
366 | directs the resource owner to an authorization server (via its
367 | user-agent as defined in [RFC2616]), which in turn directs the
368 | resource owner back to the client with the authorization code.
369 |
370 | Before directing the resource owner back to the client with the
371 | authorization code, the authorization server authenticates the
372 | resource owner and obtains authorization. Because the resource owner
373 | only authenticates with the authorization server, the resource
374 | owner's credentials are never shared with the client.
375 |
376 | The authorization code provides a few important security benefits,
377 | such as the ability to authenticate the client, as well as the
378 | transmission of the access token directly to the client without
379 | passing it through the resource owner's user-agent and potentially
380 | exposing it to others, including the resource owner.
381 | +++
382 | |[[IMPLICIT]]`IMPLICIT`|+++
383 | The implicit grant is a simplified authorization code flow optimized
384 | for clients implemented in a browser using a scripting language such
385 | as JavaScript. In the implicit flow, instead of issuing the client
386 | an authorization code, the client is issued an access token directly
387 | (as the result of the resource owner authorization). The grant type
388 | is implicit, as no intermediate credentials (such as an authorization
389 | code) are issued (and later used to obtain an access token).
390 |
391 | When issuing an access token during the implicit grant flow, the
392 | authorization server does not authenticate the client. In some
393 | cases, the client identity can be verified via the redirection URI
394 | used to deliver the access token to the client. The access token may
395 | be exposed to the resource owner or other applications with access to
396 | the resource owner's user-agent.
397 |
398 | Implicit grants improve the responsiveness and efficiency of some
399 | clients (such as a client implemented as an in-browser application),
400 | since it reduces the number of round trips required to obtain an
401 | access token. However, this convenience should be weighed against
402 | the security implications of using implicit grants, especially when the
403 | authorization code grant type is available.
404 | +++
405 | |[[PASSWORD]]`PASSWORD`|+++
406 | The resource owner password credentials (i.e., username and password)
407 | can be used directly as an authorization grant to obtain an access
408 | token. The credentials should only be used when there is a high
409 | degree of trust between the resource owner and the client (e.g., the
410 | client is part of the device operating system or a highly privileged
411 | application), and when other authorization grant types are not
412 | available (such as an authorization code).
413 |
414 | Even though this grant type requires direct client access to the
415 | resource owner credentials, the resource owner credentials are used
416 | for a single request and are exchanged for an access token. This
417 | grant type can eliminate the need for the client to store the
418 | resource owner credentials for future use, by exchanging the
419 | credentials with a long-lived access token or refresh token.
420 | +++
421 | |[[CLIENT]]`CLIENT`|+++
422 | The client credentials (or other forms of client authentication) can
423 | be used as an authorization grant when the authorization scope is
424 | limited to the protected resources under the control of the client,
425 | or to protected resources previously arranged with the authorization
426 | server. Client credentials are used as an authorization grant
427 | typically when the client is acting on its own behalf (the client is
428 | also the resource owner) or is requesting access to protected
429 | resources based on an authorization previously arranged with the
430 | authorization server.
431 | +++
432 | |[[AUTH_JWT]]`AUTH_JWT`|+++
433 | RFC7523
434 | +++
435 | |===
436 |
437 | [[ProxyType]]
438 | == ProxyType
439 |
440 | ++++
441 | The type of a TCP proxy server.
442 | ++++
443 | '''
444 |
445 | [cols=">25%,75%"]
446 | [frame="topbot"]
447 | |===
448 | ^|Name | Description
449 | |[[HTTP]]`HTTP`|+++
450 | HTTP CONNECT ssl proxy
451 | +++
452 | |[[SOCKS4]]`SOCKS4`|+++
453 | SOCKS4/4a tcp proxy
454 | +++
455 | |[[SOCKS5]]`SOCKS5`|+++
456 | SOCSK5 tcp proxy
457 | +++
458 | |===
459 |
460 | [[ReplyFailure]]
461 | == ReplyFailure
462 |
463 | ++++
464 | Represents the type of reply failure
465 | ++++
466 | '''
467 |
468 | [cols=">25%,75%"]
469 | [frame="topbot"]
470 | |===
471 | ^|Name | Description
472 | |[[TIMEOUT]]`TIMEOUT`|+++
473 | The message send failed because no reply was received before the timeout time.
474 | +++
475 | |[[NO_HANDLERS]]`NO_HANDLERS`|+++
476 | The message send failed because no handlers were available to handle the message.
477 | +++
478 | |[[RECIPIENT_FAILURE]]`RECIPIENT_FAILURE`|+++
479 | The message send failed because the recipient actively sent back a failure (rejected the message)
480 | +++
481 | |===
482 |
483 | [[ResultSetConcurrency]]
484 | == ResultSetConcurrency
485 |
486 | ++++
487 | Represents the resultset concurrency hint
488 | ++++
489 | '''
490 |
491 | [cols=">25%,75%"]
492 | [frame="topbot"]
493 | |===
494 | ^|Name | Description
495 | |[[READ_ONLY]]`READ_ONLY`|-
496 | |[[UPDATABLE]]`UPDATABLE`|-
497 | |===
498 |
499 | [[ResultSetType]]
500 | == ResultSetType
501 |
502 | ++++
503 | Represents the resultset type hint
504 | ++++
505 | '''
506 |
507 | [cols=">25%,75%"]
508 | [frame="topbot"]
509 | |===
510 | ^|Name | Description
511 | |[[FORWARD_ONLY]]`FORWARD_ONLY`|-
512 | |[[SCROLL_INSENSITIVE]]`SCROLL_INSENSITIVE`|-
513 | |[[SCROLL_SENSITIVE]]`SCROLL_SENSITIVE`|-
514 | |===
515 |
516 | [[ShiroAuthRealmType]]
517 | == ShiroAuthRealmType
518 |
519 | ++++
520 | The type of the Shiro auth realm
521 | ++++
522 | '''
523 |
524 | [cols=">25%,75%"]
525 | [frame="topbot"]
526 | |===
527 | ^|Name | Description
528 | |[[PROPERTIES]]`PROPERTIES`|+++
529 | The realm is a Shiro properties auth provider
530 | +++
531 | |[[LDAP]]`LDAP`|+++
532 | The realm is a Shiro LDAP auth provider
533 | +++
534 | |===
535 |
536 | [[TransactionIsolation]]
537 | == TransactionIsolation
538 |
539 | ++++
540 | Represents a Transaction Isolation Level
541 | ++++
542 | '''
543 |
544 | [cols=">25%,75%"]
545 | [frame="topbot"]
546 | |===
547 | ^|Name | Description
548 | |[[READ_UNCOMMITTED]]`READ_UNCOMMITTED`|+++
549 | Implements dirty read, or isolation level 0 locking, which means that no shared locks are issued and no exclusive
550 | locks are honored. When this option is set, it is possible to read uncommitted or dirty data; values in the data
551 | can be changed and rows can appear or disappear in the data set before the end of the transaction. This is the
552 | least restrictive of the four isolation levels.
553 | +++
554 | |[[READ_COMMITTED]]`READ_COMMITTED`|+++
555 | Specifies that shared locks are held while the data is being read to avoid dirty reads, but the data can be changed
556 | before the end of the transaction, resulting in nonrepeatable reads or phantom data.
557 | +++
558 | |[[REPEATABLE_READ]]`REPEATABLE_READ`|+++
559 | Locks are placed on all data that is used in a query, preventing other users from updating the data, but new
560 | phantom rows can be inserted into the data set by another user and are included in later reads in the current
561 | transaction. Because concurrency is lower than the default isolation level, use this option only when necessary.
562 | +++
563 | |[[SERIALIZABLE]]`SERIALIZABLE`|+++
564 | Places a range lock on the data set, preventing other users from updating or inserting rows into the data set until
565 | the transaction is complete. This is the most restrictive of the four isolation levels. Because concurrency is
566 | lower, use this option only when necessary.
567 | +++
568 | |[[NONE]]`NONE`|+++
569 | For engines that support it, none isolation means that each statement would essentially be its own transaction.
570 | +++
571 | |===
572 |
573 | [[Transport]]
574 | == Transport
575 |
576 | ++++
577 | The available SockJS transports
578 | ++++
579 | '''
580 |
581 | [cols=">25%,75%"]
582 | [frame="topbot"]
583 | |===
584 | ^|Name | Description
585 | |[[WEBSOCKET]]`WEBSOCKET`|+++
586 | rfc 6455
587 | +++
588 | |[[EVENT_SOURCE]]`EVENT_SOURCE`|+++
589 | Event source
590 | +++
591 | |[[HTML_FILE]]`HTML_FILE`|+++
592 | HtmlFile.
593 | +++
594 | |[[JSON_P]]`JSON_P`|+++
595 | Slow and old fashioned JSONP polling.
596 | This transport will show "busy indicator" (aka: "spinning wheel") when sending data.
597 | +++
598 | |[[XHR]]`XHR`|+++
599 | Long-polling using cross domain XHR
600 | +++
601 | |===
602 |
603 | [[UserVerification]]
604 | == UserVerification
605 |
606 |
607 | [cols=">25%,75%"]
608 | [frame="topbot"]
609 | |===
610 | ^|Name | Description
611 | |[[REQUIRED]]`REQUIRED`|-
612 | |[[PREFERRED]]`PREFERRED`|-
613 | |[[DISCOURAGED]]`DISCOURAGED`|-
614 | |===
615 |
616 | [[WebsocketVersion]]
617 | == WebsocketVersion
618 |
619 | ++++
620 | Represents the WebSocket version
621 | ++++
622 | '''
623 |
624 | [cols=">25%,75%"]
625 | [frame="topbot"]
626 | |===
627 | ^|Name | Description
628 | |[[V00]]`V00`|-
629 | |[[V07]]`V07`|-
630 | |[[V08]]`V08`|-
631 | |[[V13]]`V13`|-
632 | |===
633 |
634 | [[WriteOption]]
635 | == WriteOption
636 |
637 | ++++
638 | Enum representing the mongoDB Java Driver's link
639 | ++++
640 | '''
641 |
642 | [cols=">25%,75%"]
643 | [frame="topbot"]
644 | |===
645 | ^|Name | Description
646 | |[[ACKNOWLEDGED]]`ACKNOWLEDGED`|+++
647 |
648 | +++
649 | |[[UNACKNOWLEDGED]]`UNACKNOWLEDGED`|+++
650 |
651 | +++
652 | |[[FSYNCED]]`FSYNCED`|+++
653 |
654 | +++
655 | |[[JOURNALED]]`JOURNALED`|+++
656 |
657 | +++
658 | |[[REPLICA_ACKNOWLEDGED]]`REPLICA_ACKNOWLEDGED`|+++
659 |
660 | +++
661 | |[[MAJORITY]]`MAJORITY`|+++
662 |
663 | +++
664 | |===
665 |
666 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/clojure/io/vertx/lang/clojure/json.clj:
--------------------------------------------------------------------------------
1 | ;json wrapper of io.vertx.core.json.JsonObject & io.vertx.core.json.JsonArray
2 |
3 | (ns io.vertx.lang.clojure.json)
4 |
5 | (import io.vertx.core.json.JsonObject)
6 | (import io.vertx.core.json.JsonArray)
7 | (import io.vertx.lang.clojure.Json)
8 |
9 | (defn new-json-array
10 | ([] (new JsonArray))
11 | ([list] (new JsonArray list)))
12 | (defn new-json-object
13 | ([] (new JsonObject))
14 | ([map] (new JsonObject map)))
15 | (defn new-instance [] (new-json-object))
16 | ;put key-value pair to a jsonobject
17 | (defn put [^JsonObject json field value] (.put json field value))
18 | ;insert value to specific position of a jsonarray
19 | (defn insert [^JsonArray json index value] (.add (.getList json) index value) json)
20 | ;set allows both jsonobject and jsonarray to be set, translate put for jsonobject, add/insert for jsonarray
21 | (defn set [json field-or-pos value] (Json/set json field-or-pos value))
22 | ;get value in specific pos or field, return nil if does not exist
23 | (defn get-value [json field-or-pos] (Json/get json field-or-pos))
24 | ;abbrevation for get-value function
25 | (defn get [json field-or-pos] (get-value json field-or-pos))
26 | ;add value to the jsonarray
27 | (defn add-value [^JsonArray array value] (.add array value))
28 | ;abbrevation for add-value function
29 | (defn add [^JsonArray array & values] (reduce add-value array values))
30 | ;remove method and return removed object from the collection
31 | (defn remove [json field-or-pos] (Json/remove json field-or-pos))
32 | ;delete one single element
33 | (defn delete-element [json field-or-pos]
34 | (remove json field-or-pos)
35 | json)
36 | ;delete will return json rather then removed object
37 | (defn delete [json & field-or-pos]
38 | (reduce delete-element json field-or-pos))
39 | ;abbrevation for delete function
40 | (defn del [json & field-or-pos]
41 | (reduce delete-element json field-or-pos))
42 |
43 | (defn size [json] (.size json))
44 |
45 | (defn length [json] (size json))
46 | ;delete all entries with value in the jsonobj or jsonarray
47 | (defn delete-value [json value] (Json/removeValue json value))
48 | ;delete all entries with multiple values
49 | (defn delete-values [json & values] (reduce delete-value json values))
50 |
51 | (defn key-set [^JsonObject json]
52 | (into #{} (.keySet (.getMap json))))
53 |
54 | (defn values [json]
55 | (into [] (Json/values json)))
56 |
57 | (defn encode [obj]
58 | (Json/encode obj))
59 |
60 | (defn encode-prettily [obj]
61 | (Json/encodePrettily obj))
62 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/clojure/io/vertx/lang/clojure/logging.clj:
--------------------------------------------------------------------------------
1 | (ns io.vertx.lang.clojure.logging)
2 |
3 |
4 | (import io.vertx.core.logging.Logger)
5 | (import io.vertx.core.logging.LoggerFactory)
6 |
7 | (defn create-logger
8 | ([^String name] (LoggerFactory/getLogger name)))
9 |
10 | (defn info
11 | ([^Logger logger message] (.info logger message))
12 | ([^Logger logger message & rest] (.info logger message rest)))
13 |
14 | (defn trace
15 | ([^Logger logger message] (.trace logger message))
16 | ([^Logger logger message & rest] (.trace logger message rest)))
17 |
18 | (defn debug
19 | ([^Logger logger message] (.debug logger message))
20 | ([^Logger logger message & rest] (.debug logger message rest)))
21 |
22 | (defn warn
23 | ([^Logger logger message] (.warn logger message))
24 | ([^Logger logger message & rest] (.warn logger message rest)))
25 |
26 | (defn error
27 | ([^Logger logger message] (.error logger message))
28 | ([^Logger logger message & rest] (.error logger message rest)))
29 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/clojure/io/vertx/lang/clojure/verticle.clj:
--------------------------------------------------------------------------------
1 | (ns io.vertx.lang.clojure.verticle
2 | (:require
3 | [io.vertx.clojure.core.vertx :as vertx]))
4 |
5 | (defn get-method-parameters [f]
6 | (first (->> f meta :arglists)))
7 |
8 | (defn exists [name]
9 | (resolve (symbol name)))
10 |
11 | (defmacro completion-handler [f]
12 | `(vertx/handler
13 | (fn [r#]
14 | (vertx/handler ~f))))
15 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/java/io/vertx/lang/clojure/ClojureDocGenerator.java:
--------------------------------------------------------------------------------
1 | package io.vertx.lang.clojure;
2 |
3 | //import io.vertx.docgen.Coordinate;
4 | import io.vertx.docgen.DocGenerator;
5 | import io.vertx.docgen.JavaDocGenerator;
6 |
7 | import javax.annotation.processing.ProcessingEnvironment;
8 | import javax.lang.model.element.Element;
9 | import javax.lang.model.element.ExecutableElement;
10 | import javax.lang.model.element.TypeElement;
11 | import javax.lang.model.element.VariableElement;
12 |
13 | /**
14 | * Clojure document generator
15 | *
16 | * @author Chengen Zhao
17 | */
18 | public class ClojureDocGenerator implements DocGenerator {
19 |
20 | private JavaDocGenerator javaGen = new JavaDocGenerator();
21 |
22 | @Override
23 | public void init(ProcessingEnvironment processingEnv) {
24 | javaGen.init(processingEnv);
25 | }
26 |
27 | @Override
28 | public String getName() {
29 | return "clojure";
30 | }
31 |
32 | @Override
33 | public String renderSource(ExecutableElement elt, String source) {
34 | // ClojureLang lang = new ClojureLang();
35 | try {
36 | return source;//translator.translate(elt, lang);
37 | } catch (Exception e) {
38 | System.out.println("Cannot generate " + elt.getEnclosingElement().getSimpleName() + "#" + elt.getSimpleName() + " : " + e.getMessage());
39 | return "Code not translatable";
40 | }
41 | }
42 |
43 | @Override
44 | public String resolveTypeLink(TypeElement elt) {
45 | return javaGen.resolveTypeLink(elt);
46 | }
47 |
48 | @Override
49 | public String resolveConstructorLink(ExecutableElement elt) {
50 | return javaGen.resolveConstructorLink(elt);
51 | }
52 |
53 | @Override
54 | public String resolveMethodLink(ExecutableElement elt) {
55 | return javaGen.resolveMethodLink(elt);
56 | }
57 |
58 | @Override
59 | public String resolveLabel(Element elt, String defaultLabel) {
60 | return javaGen.resolveLabel(elt, defaultLabel);
61 | }
62 |
63 | @Override
64 | public String resolveFieldLink(VariableElement elt) {
65 | return javaGen.resolveFieldLink(elt);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/java/io/vertx/lang/clojure/ClojureVerticle.java:
--------------------------------------------------------------------------------
1 | package io.vertx.lang.clojure;
2 |
3 | import clojure.java.api.Clojure;
4 | import clojure.lang.*;
5 | import io.vertx.core.*;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | /**
11 | * Clojure language wrapper verticle, when the verticle is generated
12 | * it will automatically load the corresponding Clojure namespace file
13 | * and load its start method, currently supports several ways of start
14 | * start[] start[vertx] start[vertx context] start[context] start[context vertx]
15 | *
16 | * @author Chengen Zhao
17 | * @author Sébastien Le Callonnec
18 | */
19 | public class ClojureVerticle implements Verticle {
20 |
21 | private static final String NS_IO_VERTX_LANG_CLOJURE_VERTICLE = "io.vertx.lang.clojure.verticle";
22 |
23 | private String ns;
24 | private Vertx vertx;
25 | private Context context;
26 |
27 | private boolean requireCompiling;
28 |
29 | public ClojureVerticle(String ns) {
30 | this(ns, false);
31 | }
32 |
33 | public ClojureVerticle(String ns, boolean requireCompiling) {
34 | this.ns = ns;
35 | this.requireCompiling = requireCompiling;
36 | }
37 |
38 | @Override
39 | public Vertx getVertx() {
40 | return vertx;
41 | }
42 |
43 | @Override
44 | public void init(Vertx vertx, Context context) {
45 | this.vertx = vertx;
46 | this.context = context;
47 | }
48 |
49 | @Override
50 | public void start(Promise startFuture) {
51 |
52 | try {
53 | if (requireCompiling) {
54 | //concurrently compile clj files may cause exception,make it serial
55 | synchronized (Clojure.class) {
56 | start();
57 | }
58 | } else {//the source file should have already been compiled
59 | start();
60 | }
61 |
62 | startFuture.complete();
63 | } catch (Throwable e) {
64 | startFuture.fail(e);
65 | }
66 | }
67 |
68 | private void start() {
69 | try {
70 | final IFn require = Clojure.var("clojure.core", "require");
71 | require.invoke(Symbol.intern(NS_IO_VERTX_LANG_CLOJURE_VERTICLE));
72 | require.invoke(Symbol.intern(ns));
73 |
74 | IFn iFn = Clojure.var(NS_IO_VERTX_LANG_CLOJURE_VERTICLE, "exists");
75 | if (iFn.invoke(ns + "/start") == null)
76 | throw new RuntimeException("start method e.g.(defn start[vertx] (println vertx)) does not exist.");
77 |
78 |
79 | Map objectMap = new HashMap() {{
80 | put("vertx", vertx);
81 | put("context", context);
82 | }};
83 |
84 | IFn startIFn = Clojure.var(ns, "start");
85 | IFn getInfo = Clojure.var(NS_IO_VERTX_LANG_CLOJURE_VERTICLE, "get-method-parameters");
86 |
87 | String rawParams = getInfo.invoke(startIFn).toString();
88 | rawParams = rawParams.trim().substring(1, rawParams.length() - 1);
89 | String[] paramNames = rawParams.split(" ");
90 | switch (paramNames.length) {
91 | case 1:
92 | startIFn.invoke(objectMap.get(paramNames[0]));
93 | break;
94 | case 2:
95 | startIFn.invoke(objectMap.get(paramNames[0]), objectMap.get(paramNames[1]));
96 | break;
97 | default:
98 | startIFn.invoke();
99 | break;
100 | }
101 | } catch (Exception e) {
102 | e.printStackTrace();
103 | }
104 | }
105 |
106 | @Override
107 | public void stop(Promise stopFuture) {
108 | try {
109 | synchronized (Clojure.class) {
110 | IFn iFn = Clojure.var("clojure.core", "require");
111 | iFn.invoke(Clojure.read(NS_IO_VERTX_LANG_CLOJURE_VERTICLE));
112 |
113 | iFn = Clojure.var("clojure.core", "require");
114 | iFn.invoke(Clojure.read(ns));
115 |
116 | iFn = Clojure.var(NS_IO_VERTX_LANG_CLOJURE_VERTICLE, "exists");
117 | if (iFn.invoke(ns + "/stop") == null) {
118 | stopFuture.complete();
119 | return;
120 | }
121 |
122 | Map objectMap = new HashMap() {{
123 | put("vertx", vertx);
124 | put("context", context);
125 | }};
126 |
127 | IFn stopIFn = Clojure.var(ns, "stop");
128 | IFn getInfo = Clojure.var(NS_IO_VERTX_LANG_CLOJURE_VERTICLE, "get-method-parameters");
129 | String rawParams = getInfo.invoke(stopIFn).toString();
130 | rawParams = rawParams.trim().substring(1, rawParams.length() - 1);
131 | String[] paramNames = rawParams.split(" ");
132 | switch (paramNames.length) {
133 | case 1:
134 | stopIFn.invoke(objectMap.get(paramNames[0]));
135 | break;
136 | case 2:
137 | stopIFn.invoke(objectMap.get(paramNames[0]), objectMap.get(paramNames[1]));
138 | break;
139 | default:
140 | stopIFn.invoke();
141 | break;
142 | }
143 | }
144 | stopFuture.complete();
145 | } catch (Throwable e) {
146 | stopFuture.fail(e);
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/java/io/vertx/lang/clojure/ClojureVerticleFactory.java:
--------------------------------------------------------------------------------
1 | package io.vertx.lang.clojure;
2 |
3 | import io.vertx.core.Promise;
4 | import io.vertx.core.Verticle;
5 | import io.vertx.core.Vertx;
6 | import io.vertx.core.spi.VerticleFactory;
7 |
8 | import java.io.File;
9 | import java.util.concurrent.Callable;
10 |
11 | /**
12 | * Clojure language wrapper verticle factory, when the verticle is generated
13 | * it will automatically load the corresponding Clojure namespace file
14 | * and load its start method, currently supports several ways of start
15 | * start[] start[vertx] start[vertx context] start[context] start[context vertx]
16 | *
17 | * @author Chengen Zhao
18 | * @author Sébastien Le Callonnec
19 | */
20 | public class ClojureVerticleFactory implements VerticleFactory {
21 |
22 | private Vertx vertx;
23 |
24 | @Override
25 | public String prefix() {
26 | return "clj";
27 | }
28 |
29 | @Override
30 | public void init(Vertx vertx) {
31 | this.vertx = vertx;
32 | }
33 |
34 | @Override
35 | public void createVerticle(String verticleName, ClassLoader classLoader, Promise> promise) {
36 |
37 | String ns = VerticleFactory.removePrefix(verticleName);
38 | boolean requireCompiling = false;
39 |
40 | if (ns.endsWith("." + prefix())) {
41 | ns = ns.substring(0, ns.indexOf("." + prefix()));
42 | //check .clj source file exists, if file exists, Clojure will try to compile it
43 | //and concurrently compile clojure files may cause exception, it has to be serial
44 | String filePath = ns.replace(".", File.separator) + "." + prefix();
45 | if (classLoader.getResource(filePath) != null) {
46 | requireCompiling = true;
47 | }
48 | }
49 |
50 | //change SNAKE_CASE to KEBAB_CASE since in the namespace, clojure uses Kebab case, while Snake case in file name.
51 | ns = ns.replace("_", "-");
52 | final ClojureVerticle verticle = new ClojureVerticle(ns, requireCompiling);
53 |
54 | promise.complete(() -> verticle);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/java/io/vertx/lang/clojure/Json.java:
--------------------------------------------------------------------------------
1 | package io.vertx.lang.clojure;
2 |
3 | import io.vertx.core.json.JsonArray;
4 | import io.vertx.core.json.JsonObject;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Iterator;
8 | import java.util.List;
9 |
10 | /**
11 | * Clojure Json corresponding util class
12 | *
13 | * @author Chengen Zhao
14 | */
15 | public class Json {
16 | public static Object set(JsonArray jsonArray, int pos, Object value) {
17 | List list = jsonArray.getList();
18 | if (pos > list.size()) list.add(value);
19 | else list.add(pos, value);
20 | return jsonArray;
21 | }
22 |
23 | public static Object set(JsonObject jsonObject, String key, Object value) {
24 | return jsonObject.put(key, value);
25 | }
26 |
27 | public static Object get(JsonArray jsonArray, int pos) {
28 | if (pos >= jsonArray.size()) return null;
29 | return jsonArray.getValue(pos);
30 | }
31 |
32 | public static Object get(JsonObject jsonObject, String key) {
33 | return jsonObject.getValue(key);
34 | }
35 |
36 | public static Object remove(JsonArray jsonArray, int pos) {
37 | if (pos >= jsonArray.size()) return null;
38 | return jsonArray.remove(pos);
39 | }
40 |
41 | public static Object remove(JsonObject jsonObject, String key) {
42 | return jsonObject.remove(key);
43 | }
44 |
45 | public static Object removeValue(JsonArray jsonArray, Object value) {
46 | Iterator iterator = jsonArray.iterator();
47 | while (iterator.hasNext()) {
48 | Object obj = iterator.next();
49 | if (obj == value || obj.equals(value)) {
50 | iterator.remove();
51 | }
52 | }
53 | return jsonArray;
54 | }
55 |
56 | public static Object removeValue(JsonObject jsonObject, Object value) {
57 | jsonObject.getMap().entrySet().removeIf(entry -> (entry.getValue() == value || entry.getValue().equals(value)));
58 | return jsonObject;
59 | }
60 |
61 | public static Object values(JsonObject jsonObject) {
62 | return jsonObject.getMap().values();
63 | }
64 |
65 | public static Object values(JsonArray jsonArray) {
66 | return jsonArray.getList();
67 | }
68 |
69 | public static Object keySet(JsonObject jsonObject) {
70 | return jsonObject.getMap().keySet();
71 | }
72 |
73 | public static Object keySet(JsonArray jsonArray) {
74 | List list = new ArrayList();
75 | for (int i = 0; i < jsonArray.size(); i++) {
76 | list.add(i);
77 | }
78 | return list;
79 | }
80 |
81 | public static String encode(Object obj) {
82 | return io.vertx.core.json.Json.encode(obj);
83 | }
84 |
85 | public static String encodePrettily(Object obj) {
86 | return io.vertx.core.json.Json.encodePrettily(obj);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/resources/META-INF/services/io.vertx.core.spi.VerticleFactory:
--------------------------------------------------------------------------------
1 | io.vertx.lang.clojure.ClojureVerticleFactory
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/resources/META-INF/services/io.vertx.docgen.DocGenerator:
--------------------------------------------------------------------------------
1 | io.vertx.lang.clojure.ClojureDocGenerator
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/resources/vertx-clojure/template/class.templ:
--------------------------------------------------------------------------------
1 | (ns @{type.raw.translatePackageName("clojure")}.@{type.raw.getSimpleName(CASE_KEBAB)})\n
2 | @code{
3 | /*clojure does not allow different functions with the same name, thus combine the functions with the same name first
4 | use their name as map key, methods as value list*/
5 | import java.util.TreeMap;
6 | import java.util.HashMap;
7 | import java.util.TreeSet;
8 | import java.util.ArrayList;
9 | /*using tree map & set here only because we need to keep the order in source files*/
10 | var methodsMap = new TreeMap();
11 | var paramsMap = new HashMap();
12 | var importClassSet = new TreeSet();
13 | foreach (method : methods) {
14 | if(methodsMap[method.name] == null){
15 | methodsMap[method.name] = [method];
16 | var params = new ArrayList();
17 | for(param:method.params){
18 | params.add(param.name);
19 | }
20 | paramsMap[method.name +"-"+params.size()] = params;
21 | }else{
22 | /*Can't have 2 overloads with same arity, the method with same name and params numbers will be combined
23 | e.g. (req [uri] ...)& (req [options] ...) -> (req [uri-or-options] ...)*/
24 | var thereIsAnExistingMethodWithSameParameterNumber = false;
25 |
26 | if(paramsMap[method.name+"-"+method.params.size()] != null){
27 | thereIsAnExistingMethodWithSameParameterNumber = true;
28 |
29 | var list = new ArrayList();
30 |
31 | var paramNames = paramsMap[method.name+"-"+method.params.size()];
32 | var params = method.params;
33 | /*combine parameters' name e.g. option-or-request-uri*/
34 | for(int j=0;j0} @end{}@foreach{param:paramsMap[methodName+"-"+paramsSize]}@{CASE_KEBAB.format(CASE_CAMEL.parse(param))}@end{' '}
106 | )
107 | @else{}
108 | [@{type.raw.getSimpleName(CASE_KEBAB)}@if{paramsSize>0} @end{}@foreach{param:paramsMap[methodName+"-"+paramsSize]}@{CASE_KEBAB.format(CASE_CAMEL.parse(param))}@end{' '}] (
109 | .@{method.name} @{type.raw.getSimpleName(CASE_KEBAB)}@if{paramsSize>0} @end{}@foreach{param:paramsMap[methodName+"-"+paramsSize]}@{CASE_KEBAB.format(CASE_CAMEL.parse(param))}@end{' '}
110 | )
111 | @end{})
112 | @end{})
113 | @end{}
114 |
115 | @if{!handlerIsDefined}
116 | @foreach{name:importClassSet}
117 | @if{name == "io.vertx.core.Handler"}
118 | \n(defn handler [f]
119 | \n (reify
120 | \n io.vertx.core.Handler
121 | \n (handle [this para]
122 | \n (f para))))
123 | @end{}
124 | @end{}
125 | @end{}
126 |
127 | @if{!functionIsDefined}
128 | @foreach{name:importClassSet}
129 | @if{name == "java.util.function.Function"}
130 | \n(defn function [f]
131 | \n (reify
132 | \n java.util.function.Function
133 | \n (apply [this para]
134 | \n (f para))))
135 | @end{}
136 | @end{}
137 | @end{}
138 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/main/resources/vertx-clojure/template/dataobject.templ:
--------------------------------------------------------------------------------
1 | (ns @{type.raw.translatePackageName("clojure")}.@{type.raw.getSimpleName(CASE_KEBAB)})\n
2 | @code{
3 | var className = type.raw.getSimpleName();
4 | var objName = className.substring(0,1).toLowerCase() + className.substring(1);
5 |
6 | var classKeBabName = CASE_KEBAB.format(CASE_CAMEL.parse(className));
7 | var objKeBabName = CASE_KEBAB.format(CASE_CAMEL.parse(objName));
8 | }
9 |
10 | \n(import @{type.raw})
11 | \n(import io.vertx.core.json.JsonObject)
12 | \n
13 | \n(defn new-instance
14 | @if{hasEmptyConstructor}\n ([] (new @{type.raw.getSimpleName()}))@end{}
15 | \n ([^JsonObject json] (new @{type.raw.getSimpleName()} json)))
16 | \n
17 | @foreach{property:properties}
18 |
19 | @code{var propertyKebabName = CASE_KEBAB.format(CASE_CAMEL.parse(property.name));}
20 |
21 | @if{property.getAdderMethod()!=null}
22 | @code{var method = property.getAdderMethod()}
23 | @if{property.kind.name == "MAP"}
24 | \n(defn @{CASE_KEBAB.format(CASE_CAMEL.parse(method))} [^@{className} @{objKeBabName} key value] (.@{method} @{objKeBabName} key value))
25 | @else{}
26 | \n(defn @{CASE_KEBAB.format(CASE_CAMEL.parse(method))} [^@{className} @{objKeBabName} @{propertyKebabName}] (.@{method} @{objKeBabName} @{propertyKebabName}))
27 | @end{}
28 | @end{}
29 |
30 | @if{property.getSetterMethod()!=null}
31 | @code{var method = property.getSetterMethod()}
32 | \n(defn @{CASE_KEBAB.format(CASE_CAMEL.parse(method))} [^@{className} @{objKeBabName} @{propertyKebabName}] (.@{method} @{objKeBabName} @{propertyKebabName}))
33 | @end{}
34 |
35 | @if{property.getGetterMethod()!=null}
36 | @code{var method = property.getGetterMethod()}
37 | \n(defn @{CASE_KEBAB.format(CASE_CAMEL.parse(method))} [^@{className} @{objKeBabName}] (.@{method} @{objKeBabName}))
38 | @end{}
39 |
40 | @end{}
41 |
42 | @if{hasToJsonMethod}
43 | \n(defn to-json [^@{className} @{objKeBabName}] (.toJson @{objKeBabName}))
44 | @end{}
45 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/test/clojure/com/acme/clojure/pkg/my_interface.clj:
--------------------------------------------------------------------------------
1 | (ns com.acme.clojure.pkg.my-interface)
2 |
3 | (import com.acme.pkg.MyInterface)
4 |
5 | (defn create
6 | ([] (MyInterface/create)))
7 | (defn method
8 | ([my-interface] (.method my-interface)))
9 | (defn sub
10 | ([my-interface] (.sub my-interface)))
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/test/clojure/com/acme/clojure/pkg/sub/sub_interface.clj:
--------------------------------------------------------------------------------
1 | (ns com.acme.clojure.pkg.sub.sub-interface)
2 |
3 | (import com.acme.pkg.sub.SubInterface)
4 |
5 | (defn reverse
6 | ([sub-interface s] (.reverse sub-interface s)))
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/test/clojure/io/vertx/lang/clojure/json_test.clj:
--------------------------------------------------------------------------------
1 | (ns io.vertx.lang.clojure.json-test
2 | (:require [clojure.test :as test]
3 | [io.vertx.lang.clojure.json :as json]))
4 |
5 | (test/deftest test-json-object
6 | (let [json (json/new-instance)]
7 | (-> json
8 | (json/put "age" 30)
9 | (json/put "country" "cn")
10 | (json/put "male" true)
11 | (json/put "height" 181.5)
12 | (json/put "redundant" "redundant")
13 | (json/del "redundant" "male")
14 | (json/put "redundant" "not really"))
15 | (test/is (= 30 (json/get json "age")))
16 | (test/is (= "cn" (json/get json "country")))
17 | (test/is (< 180 (json/get json "height")))
18 | (test/is (= nil (json/get json "male")))
19 | (test/is (= 4 (json/size json)))))
20 |
21 | (test/deftest test-json-array
22 | (let [array (json/new-json-array)]
23 | (json/add array 1)
24 | (test/is (= 1 (json/get array 0)))
25 | (json/add array 1 3 5 7 9)
26 | (test/is (= 3 (json/get array 2)))
27 | (json/del array 3 4)
28 | (test/is (= 7 (json/get array 3)))
29 | (test/is (= 4 (json/size array)))))
30 |
31 | (test/deftest test-json-delete
32 | (let [obj (json/new-json-object)
33 | array (json/new-json-array)]
34 |
35 | (-> obj
36 | (json/put "age" 30)
37 | (json/put "male" false)
38 | (json/put "height" 181.5)
39 | (json/put "country" "cn")
40 | (json/delete-values "cn" 30))
41 | (test/is (= 2 (json/size obj)))
42 |
43 | (json/add array 1 2 "3" false true obj)
44 | (json/delete-values array "3" 2 7)
45 | (test/is (= 4 (json/size array)))))
46 |
47 | (test/deftest test-json-set
48 | (let [obj (json/new-json-object)
49 | array (json/new-json-array)]
50 | (-> array
51 | (json/set 3 1)
52 | (json/set 2 2)
53 | (json/set 1 3)
54 | (json/set 0 4)
55 | (json/insert 0 0)
56 | (json/del 1))
57 | (test/is (= 4 (json/size array)))))
58 |
59 | (test/deftest test-json-nil-return
60 | (let [obj (json/new-json-object)
61 | array (json/new-json-array)]
62 | (test/is (= nil (json/get array 3)))
63 | (test/is (= nil (json/get obj "3")))
64 | (test/is (= nil (json/remove obj "3")))
65 | (test/is (= nil (json/remove array 3)))))
66 |
67 | (test/deftest test-json-constructor
68 | (let [obj (json/new-json-object {"ok" 1 :key 2 3 2})
69 | array (json/new-json-array [1 2 3 2])]
70 | (test/is (= 1 (json/get obj "ok")))
71 | (test/is (= 2 (json/get array 1)))
72 | (test/is (= 1 (first (json/values array))))
73 | (test/is (contains? (json/key-set obj) :key))))
74 |
75 | (test/run-tests 'io.vertx.lang.clojure.json-test)
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/test/clojure/io/vertx/lang/clojure/vertx_test.clj:
--------------------------------------------------------------------------------
1 | ; (ns io.vertx.lang.clojure.vertx-test
2 | ; (:require [clojure.test :as test]
3 | ; [io.vertx.lang.clojure.json :as json]
4 | ; [io.vertx.clojure.codegen.testmodel.data-object-tck :as dot]
5 | ; [io.vertx.clojure.codegen.testmodel.data-object-with-values :as values]))
6 | ;
7 | ; (import io.vertx.codegen.testmodel.DataObjectTCKImpl)
8 | ;
9 | ; (test/deftest addition
10 | ; (test/is (= 2 (+ 1 1))))
11 | ;
12 | ; (test/run-tests 'io.vertx.lang.clojure.vertx-test)
13 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/test/java/io/vertx/lang/clojure/VerticleTest.java:
--------------------------------------------------------------------------------
1 | package io.vertx.lang.clojure;
2 |
3 | import io.vertx.core.Future;
4 | import io.vertx.core.http.*;
5 | import io.vertx.test.core.VertxTestBase;
6 | import org.junit.Test;
7 |
8 | public class VerticleTest extends VertxTestBase {
9 |
10 | @Test
11 | public void testHttpServer() {
12 | vertx.deployVerticle("examples.simple_http_server.clj", ar -> {
13 | assertTrue(ar.succeeded());
14 |
15 | HttpClient client = vertx.createHttpClient(new HttpClientOptions().setLogActivity(true));
16 | client.request(HttpMethod.GET, 8080, "localhost", "/", ar1 -> {
17 | if (ar1.succeeded()) {
18 | assertTrue(true);
19 | } else {
20 | fail();
21 | }
22 | testComplete();
23 | });
24 | });
25 | await();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/vertx-lang-clojure/src/test/resources/examples/simple_http_server.clj:
--------------------------------------------------------------------------------
1 | (ns examples.simple-http-server
2 | (:require [io.vertx.clojure.core.vertx :as vertx]
3 | [io.vertx.clojure.core.http.http-server :as server]
4 | [io.vertx.clojure.core.http.http-server-request :as request]
5 | [io.vertx.clojure.core.http.http-server-response :as response]))
6 |
7 | (defn handle-request [req]
8 | (let [response (request/response req)]
9 | (-> response
10 | (response/put-header "content-type" "text/plain")
11 | (response/end "Hello from Vert.x!"))))
12 |
13 | (defn start [vertx]
14 | (let [http-server (vertx/create-http-server vertx)]
15 | (-> http-server
16 | (server/request-handler (vertx/handler handle-request))
17 | (server/listen 8080))))
18 |
--------------------------------------------------------------------------------