├── .editorconfig ├── .gitignore ├── README.md ├── pom.xml ├── vertx-lang-clojure-gen ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── vertx │ │ └── lang │ │ └── clojure │ │ ├── AbstractClojureCodeGenerator.java │ │ ├── ClojureClassGenerator.java │ │ ├── ClojureDataObjectGenerator.java │ │ ├── ClojureGeneratorLoader.java │ │ └── utils │ │ └── ClojureUtils.java │ └── resources │ └── META-INF │ └── services │ └── io.vertx.codegen.GeneratorLoader └── vertx-lang-clojure ├── pom.xml └── src ├── main ├── asciidoc │ ├── clojure │ │ ├── buffers.adoc │ │ ├── cli-for-java.adoc │ │ ├── cli.adoc │ │ ├── datagrams.adoc │ │ ├── dns.adoc │ │ ├── eventbus.adoc │ │ ├── filesystem.adoc │ │ ├── http.adoc │ │ ├── index.adoc │ │ ├── net.adoc │ │ ├── parsetools.adoc │ │ ├── shareddata.adoc │ │ └── streams.adoc │ ├── dataobjects.adoc │ └── enums.adoc ├── clojure │ └── io │ │ └── vertx │ │ └── lang │ │ └── clojure │ │ ├── json.clj │ │ ├── logging.clj │ │ └── verticle.clj ├── java │ └── io │ │ └── vertx │ │ └── lang │ │ └── clojure │ │ ├── ClojureDocGenerator.java │ │ ├── ClojureVerticle.java │ │ ├── ClojureVerticleFactory.java │ │ └── Json.java └── resources │ ├── META-INF │ └── services │ │ ├── io.vertx.core.spi.VerticleFactory │ │ └── io.vertx.docgen.DocGenerator │ └── vertx-clojure │ └── template │ ├── class.templ │ └── dataobject.templ └── test ├── clojure ├── com │ └── acme │ │ └── clojure │ │ └── pkg │ │ ├── my_interface.clj │ │ └── sub │ │ └── sub_interface.clj └── io │ └── vertx │ └── lang │ └── clojure │ ├── json_test.clj │ └── vertx_test.clj ├── java └── io │ └── vertx │ └── lang │ └── clojure │ └── VerticleTest.java └── resources └── examples └── simple_http_server.clj /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 4 7 | trim_trailing_whitespace = true 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [*.{js,css,html,xml,rb}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.{org}] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | target 3 | 4 | *.iml 5 | 6 | # Generated code 7 | vertx-lang-clojure/src/main/clojure/io/vertx/clojure 8 | vertx-lang-clojure/src/test/clojure/io/vertx/clojure 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vertx-lang-clojure 2 | Vert.x Clojure support. 3 | 4 | This version has not been submitted to Maven Central, so you need to `mvn install` to use. 5 | See https://github.com/tychobrailleur/vertx-lang-clojure-example for examples of usage. 6 | 7 | Known problem: vertx-lang-clojure has a conflict with datomic in netty-transport-native 8 | 9 | ### How to use? 10 | 11 | In vertx-lang-clojure-gen/, run `mvn install` first. 12 | 13 | Go back to vertx-lang-clojure/, run `mvn install` subsequently. 14 | 15 | Maven (in your pom.xml): 16 | ```xml 17 | 18 | com.sparcing 19 | vertx-lang-clojure 20 | 4.5.13 21 | 22 | ``` 23 | 24 | Leiningen (in your `project.clj`): 25 | 26 | ```clojure 27 | :dependencies [[org.clojure/clojure "1.11.4"] 28 | [io.vertx/vertx-web "4.5.13"] 29 | [com.sparcing/vertx-lang-clojure "4.5.13"]] 30 | ``` 31 | 32 | 33 | ### Hello from Vert.x! 34 | 35 | ```clojure 36 | (ns example.server 37 | (:require [io.vertx.clojure.core.vertx :as vertx] 38 | [io.vertx.clojure.core.http.http-server :as server] 39 | [io.vertx.clojure.core.http.http-server-request :as request] 40 | [io.vertx.clojure.core.http.http-server-response :as response])) 41 | 42 | (defn handle-request [req] 43 | (let [response (request/response req)] 44 | (-> response 45 | (response/put-header "content-type" "text/plain") 46 | (response/end "Hello from Vert.x!")))) 47 | 48 | (defn start [vertx] 49 | (let [http-server (vertx/create-http-server vertx)] 50 | (-> http-server 51 | (server/request-handler (vertx/handler handle-request)) 52 | (server/listen 8080)))) 53 | ``` 54 | 55 | ### Vert.x instance 56 | 57 | If you’re embedding Vert.x then you simply create an instance as follows: 58 | 59 | ```clojure 60 | (ns ... 61 | (:require [io.vertx.clojure.core.vertx :as vertx])) 62 | 63 | ;create a vertx instance 64 | (vertx/vertx) 65 | ``` 66 | 67 | ### Verticle 68 | 69 | Verticle namespace files normally include a start function which is the entry point of verticle deployment. 70 | 71 | Here’s an example verticle: 72 | ```clojure 73 | 74 | ;Called when verticle is deployed 75 | (defn start []) 76 | 77 | ;Optional - called when verticle is undeployed 78 | (defn stop []) 79 | ``` 80 | 81 | When Vert.x deploys the verticle it will call the start method, and when the method has completed the verticle will be considered started. 82 | 83 | You can also optionally provide vertx and context parameters. This will be used by developers when the functions are considered pure. 84 | 85 | ```clojure 86 | 87 | ;Following functions format are all allowed, pick one. 88 | (defn start [context vertx]) 89 | (defn start [vertx context]) 90 | (defn start [vertx]) 91 | (defn start [context]) 92 | 93 | ;Following functions format are all allowed, pick one. 94 | (defn stop [context vertx]) 95 | (defn stop [vertx context]) 96 | (defn stop [vertx]) 97 | (defn stop [context]) 98 | 99 | ``` 100 | 101 | ### Verticle Deployment 102 | 103 | A Clojure verticle can be deployed with `.clj` suffix or `clj:` prefix: 104 | 105 | ```clojure 106 | (ns example.verticle 107 | (:require [io.vertx.clojure.core.vertx :as vertx])) 108 | 109 | ; completion-handler is required to start the verticle 110 | (def my-handler 111 | (verticle/completion-handler #(println %))) 112 | 113 | (defn start [vertx] 114 | (vertx/deploy-verticle vertx "io.vertx.sample_verticle.clj" my-handler)) 115 | ;or 116 | (defn start [vertx] 117 | (vertx/deploy-verticle vertx "clj:io.vertx.sample_verticle" my-handler)) 118 | ``` 119 | 120 | ;TODO 121 | 122 | - [x] Auto-generate thin wrap APIs by using Codegen 123 | - [x] VerticleWrapper of generated APIs(ClojureVerticle for .clj suffix namespaces) 124 | - [x] ClojureVerticleFactory service 125 | - [x] Tests 126 | - [ ] Auto-generate docs by using Docgen 127 | - [ ] Using Codox to generate on-line Clojure documentation 128 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | io.vertx 7 | vertx-parent 8 | 19 9 | 10 | 11 | com.sparcing 12 | vertx-lang-clojure-parent 13 | 4.5.7 14 | pom 15 | 16 | 17 | vertx-lang-clojure-gen 18 | vertx-lang-clojure 19 | 20 | 21 | Vert.x Clojure Implementation 22 | https://github.com/tychobrailleur/vertx-lang-clojure 23 | 24 | 25 | 26 | The Apache Software License, Version 2.0 27 | http://www.apache.org/licenses/LICENSE-2.0.txt 28 | repo 29 | 30 | 31 | Eclipse Public License - v1.0 32 | http://www.eclipse.org/legal/epl-v10.html 33 | repo 34 | 35 | 36 | 37 | 38 | scm:git:git@github.com:tychobrailleur/vertx-lang-clojure.git 39 | scm:git:git@github.com:tychobrailleur/vertx-lang-clojure.git 40 | git@github.com:tychobrailleur/vertx-lang-clojure.git 41 | 42 | 43 | 44 | 45 | minosniu 46 | Sparcing 47 | niuchuanxin@sparcing.com 48 | 49 | 50 | 51 | 52 | UTF-8 53 | 1.11.4 54 | 1.8.4 55 | 4.13 56 | 4.5.7 57 | 58 | 59 | 60 | 61 | 62 | org.clojure 63 | clojure 64 | ${clojure.version} 65 | 66 | 67 | io.vertx 68 | vertx-dependencies 69 | ${stack.version} 70 | pom 71 | import 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | org.apache.maven.plugins 81 | maven-javadoc-plugin 82 | 3.2.0 83 | 84 | 85 | org.apache.maven.plugins 86 | maven-dependency-plugin 87 | 3.1.2 88 | 89 | 90 | org.asciidoctor 91 | asciidoctor-maven-plugin 92 | 1.5.8 93 | 94 | 95 | org.bsc.maven 96 | maven-processor-plugin 97 | 4.0 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | release 106 | 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-gpg-plugin 111 | 1.6 112 | 113 | 114 | sign-artifacts 115 | verify 116 | 117 | sign 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | 7 | com.sparcing 8 | vertx-lang-clojure-parent 9 | 4.5.7 10 | 11 | 12 | vertx-lang-clojure-gen 13 | 4.5.7 14 | 15 | 16 | UTF-8 17 | 18 | 19 | 20 | 21 | io.vertx 22 | vertx-codegen 23 | provided 24 | 25 | 26 | io.vertx 27 | vertx-docgen 28 | true 29 | 30 | 31 | io.vertx 32 | vertx-codegen 33 | tck-sources 34 | test 35 | 36 | 37 | io.vertx 38 | vertx-codegen 39 | tck 40 | test 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/src/main/java/io/vertx/lang/clojure/AbstractClojureCodeGenerator.java: -------------------------------------------------------------------------------- 1 | package io.vertx.lang.clojure; 2 | 3 | import io.vertx.codegen.Generator; 4 | import io.vertx.codegen.Model; 5 | import io.vertx.codegen.format.CamelCase; 6 | import io.vertx.codegen.format.SnakeCase; 7 | 8 | public class AbstractClojureCodeGenerator extends Generator { 9 | final String generated = "clojure/"; 10 | 11 | @Override 12 | public String filename(T model) { 13 | final String moduleName = model.getModule().translateQualifiedName(model.getFqn(), "clojure"); 14 | return generated + SnakeCase.INSTANCE.format(CamelCase.INSTANCE.parse(moduleName)) 15 | .replace("._", ".") 16 | .replace(".", "/") + ".clj"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/src/main/java/io/vertx/lang/clojure/ClojureClassGenerator.java: -------------------------------------------------------------------------------- 1 | package io.vertx.lang.clojure; 2 | 3 | import io.vertx.codegen.*; 4 | import io.vertx.codegen.format.KebabCase; 5 | import io.vertx.codegen.writer.CodeWriter; 6 | import io.vertx.lang.clojure.utils.ClojureUtils; 7 | 8 | import java.io.StringWriter; 9 | import java.util.*; 10 | import java.util.function.BiConsumer; 11 | import java.util.stream.Collectors; 12 | 13 | import static io.vertx.lang.clojure.utils.ClojureUtils.*; 14 | 15 | public class ClojureClassGenerator extends AbstractClojureCodeGenerator { 16 | private boolean handlerRendered; 17 | private boolean functionRendered; 18 | 19 | public ClojureClassGenerator() { 20 | super(); 21 | this.name = "Clojure"; 22 | this.kinds = Collections.singleton("class"); 23 | } 24 | 25 | @Override 26 | public String render(ClassModel model, int index, int size, Map session) { 27 | handlerRendered = false; 28 | functionRendered = false; 29 | 30 | final StringWriter buffer = new StringWriter(); 31 | final CodeWriter writer = new CodeWriter(buffer); 32 | writer.println("(ns " + model.getType().translatePackageName("clojure") + "." 33 | + model.getType().getRaw().getSimpleName(KebabCase.INSTANCE) + ")"); 34 | writer.println(); 35 | 36 | Set imports = new TreeSet<>(); 37 | 38 | // Mapping between function+arity and arg list 39 | Map> paramMap = new HashMap<>(); 40 | 41 | // Mapping between function and mapping function+arity and arg list 42 | Map>> methods = new HashMap<>(); 43 | 44 | model.getMethods().forEach(methodInfo -> { 45 | if (model.getMethodMap().get(methodInfo.getName()) == null) { 46 | throw new RuntimeException("Method not found! " 47 | + model.getType().getSimpleName() + "#" + methodInfo.getName()); 48 | } 49 | 50 | getImports(model, imports, methodInfo); 51 | getMethodsAndArgsName(paramMap, methods, methodInfo); 52 | }); 53 | 54 | renderImports(writer, imports); 55 | writer.println(); 56 | 57 | String className = model.getType().getRaw().getSimpleName(); 58 | String objName = className.substring(0, 1).toLowerCase() + className.substring(1); 59 | String kebabCaseObjName = clojurifyName(objName); 60 | 61 | methods.forEach(renderMethod(model, writer, className, kebabCaseObjName)); 62 | 63 | // TODO Get methods that takes Handler as arg to simply accept a one-arg function. 64 | if (imports.contains("io.vertx.core.Handler") && !handlerRendered) { 65 | renderHandlerMethod(writer); 66 | } 67 | if (imports.contains("java.util.function.Function") && !functionRendered) { 68 | renderFunctionMethod(writer); 69 | } 70 | 71 | return buffer.toString(); 72 | } 73 | 74 | private BiConsumer>> renderMethod(ClassModel model, CodeWriter writer, String className, String kebabCaseObjName) { 75 | return (methodName, value) -> { 76 | if ("handler".equals(methodName)) { 77 | renderHandlerMethod(writer); 78 | handlerRendered = true; 79 | } else if ("function".equals(methodName)) { 80 | renderFunctionMethod(writer); 81 | functionRendered = true; 82 | } else { 83 | MethodInfo methodInfo = model.getMethodMap().get(methodName).get(0); 84 | if (methodName.equals(className)) { 85 | renderCtor(model, writer, methodName, value); 86 | } else if (methodInfo.isStaticMethod()) { 87 | renderStaticMethod(model, writer, methodName, value); 88 | } else { 89 | renderMethod(writer, kebabCaseObjName, methodName, value); 90 | } 91 | } 92 | writer.println(); 93 | }; 94 | } 95 | 96 | private void renderMethod(CodeWriter writer, String kebabCaseObjName, String methodName, Map> value) { 97 | String s = clojurifyName(methodName); 98 | if (s.startsWith("is-")) { 99 | s = s.replaceAll("^is\\-", "") + "?"; 100 | } 101 | writer.print("(defn " + s); 102 | value.forEach((key, value1) -> { 103 | writer.println(); 104 | List methodArgs = new ArrayList<>(); 105 | methodArgs.add(kebabCaseObjName+"-obj"); 106 | methodArgs.addAll(value1); 107 | String args = methodArgs.stream().map(ClojureUtils::clojurifyName).collect(Collectors.joining(" ")); 108 | writer.println(" ([" + args + "]"); 109 | writer.print(" (." + methodName + " " + args + "))"); 110 | }); 111 | writer.println(")"); 112 | } 113 | 114 | private void renderStaticMethod(ClassModel model, CodeWriter writer, String methodName, Map> value) { 115 | writer.print("(defn " + clojurifyName(methodName)); 116 | value.forEach((key, value1) -> { 117 | writer.println(); 118 | String args = value1.stream().map(ClojureUtils::clojurifyName).collect(Collectors.joining(" ")); 119 | writer.println(" ([" + args + "]"); 120 | writer.print(" (" + model.getType().getRaw().getSimpleName() + "/" + methodName + " " + args + "))"); 121 | }); 122 | writer.println(")"); 123 | } 124 | 125 | private void renderCtor(ClassModel model, CodeWriter writer, String methodName, Map> value) { 126 | writer.print("(defn " + clojurifyName(methodName)); 127 | value.forEach((key, value1) -> { 128 | writer.println(); 129 | String args = value1.stream().map(ClojureUtils::clojurifyName).collect(Collectors.joining(" ")); 130 | writer.println(" ([" + args + "]"); 131 | writer.print(" (new " + model.getType().getRaw().getSimpleName() + " " + args + "))"); 132 | }); 133 | } 134 | 135 | private void renderImports(CodeWriter writer, Set imports) { 136 | imports.stream().filter(s -> s.startsWith("io.vertx") || s.startsWith("java.util")).forEach(s -> { 137 | writer.println("(import " + s + ")"); 138 | }); 139 | } 140 | 141 | private void getImports(ClassModel model, Set imports, MethodInfo methodInfo) { 142 | for (ParamInfo paramInfo: methodInfo.getParams()) { 143 | if (paramInfo.getType().getRaw() != null) { 144 | imports.add(paramInfo.getType().getRaw().getName()); 145 | } 146 | } 147 | imports.add(model.getType().getRaw().getName()); 148 | } 149 | 150 | private void getMethodsAndArgsName(Map> paramMap, Map>> methods, MethodInfo methodInfo) { 151 | String key = methodInfo.getName() + "#" + methodInfo.getParams().size(); 152 | List params = paramMap.get(key); 153 | List paramList = Collections.EMPTY_LIST; 154 | 155 | if (params == null) { 156 | paramList = methodInfo.getParams() 157 | .stream() 158 | .map(ParamInfo::getName) 159 | .collect(Collectors.toList()); 160 | } else { 161 | paramList = new ArrayList<>(); 162 | for (int i = 0; i < methodInfo.getParams().size(); i++) { 163 | if (methodInfo.getParam(i).getName().contains(params.get(i))) { 164 | paramList.add(params.get(i)); 165 | } else { 166 | paramList.add(methodInfo.getParam(i).getName() + "-or-" + params.get(i)); 167 | } 168 | } 169 | } 170 | paramMap.put(key, paramList); 171 | 172 | if (!methods.containsKey(methodInfo.getName())) { 173 | Map> methodParamMap = new HashMap<>(); 174 | methodParamMap.put(methodInfo.getName() + "#" + paramList.size(), paramList); 175 | methods.put(methodInfo.getName(), methodParamMap); 176 | } else { 177 | Map> methodsWithArity = methods.get(methodInfo.getName()); 178 | Map> methodParamMap = new HashMap<>(); 179 | methodParamMap.put(methodInfo.getName() + "#" + paramList.size(), paramList); 180 | methodsWithArity.putAll(methodParamMap); 181 | methods.put(methodInfo.getName(), methodsWithArity); 182 | } 183 | } 184 | 185 | private void renderHandlerMethod(CodeWriter writer) { 186 | writer.println("(defn handler "); 187 | writer.println(" ([f]"); 188 | writer.println(" (reify io.vertx.core.Handler"); 189 | writer.println(" (handle [this arg]"); 190 | writer.println(" (f arg)))))"); 191 | } 192 | 193 | private void renderFunctionMethod(CodeWriter writer) { 194 | writer.println("(defn function "); 195 | writer.println(" ([f]"); 196 | writer.println(" (reify java.util.function.Function"); 197 | writer.println(" (apply [this arg]"); 198 | writer.println(" (f arg)))))"); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/src/main/java/io/vertx/lang/clojure/ClojureDataObjectGenerator.java: -------------------------------------------------------------------------------- 1 | package io.vertx.lang.clojure; 2 | 3 | import io.vertx.codegen.DataObjectModel; 4 | import io.vertx.codegen.PropertyInfo; 5 | import io.vertx.codegen.format.KebabCase; 6 | import io.vertx.codegen.writer.CodeWriter; 7 | 8 | import java.io.StringWriter; 9 | import java.util.Collections; 10 | import java.util.Map; 11 | 12 | import static io.vertx.lang.clojure.utils.ClojureUtils.*; 13 | 14 | /** 15 | * Generates the Clojure code for data objects. 16 | */ 17 | public class ClojureDataObjectGenerator extends AbstractClojureCodeGenerator { 18 | 19 | 20 | public ClojureDataObjectGenerator() { 21 | super(); 22 | this.name = "Clojure"; 23 | this.kinds = Collections.singleton("dataObject"); 24 | } 25 | 26 | @Override 27 | public String render(DataObjectModel model, int index, int size, Map session) { 28 | 29 | final StringWriter buffer = new StringWriter(); 30 | final CodeWriter writer = new CodeWriter(buffer); 31 | writer.println("(ns " + model.getType().translatePackageName("clojure") + "." 32 | + model.getType().getRaw().getSimpleName(KebabCase.INSTANCE) + ")"); 33 | writer.println(); 34 | renderImport(model, writer); 35 | writer.println(); 36 | renderCtor(model, writer); 37 | 38 | String className = model.getType().getRaw().getSimpleName(); 39 | String objName = className.substring(0, 1).toLowerCase() + className.substring(1); 40 | String kebabCaseObjName = clojurifyName(objName); 41 | 42 | model.getPropertyMap().forEach((propName, propertyInfo) -> { 43 | renderProperty(writer, className, kebabCaseObjName, propName, propertyInfo); 44 | }); 45 | 46 | renderToJson(model, writer, className, kebabCaseObjName); 47 | 48 | return buffer.toString(); 49 | } 50 | 51 | private void renderCtor(DataObjectModel model, CodeWriter writer) { 52 | writer.println("(defn new-instance"); 53 | if (model.hasEmptyConstructor()) { 54 | writer.println(" ([] (new " + model.getType().getRaw().getSimpleName() + "))"); 55 | } 56 | writer.println(" ([^JsonObject json] (new " + model.getType().getRaw().getSimpleName() + " json)))"); 57 | writer.println(); 58 | } 59 | 60 | private void renderToJson(DataObjectModel model, CodeWriter writer, String className, String kebabCaseObjName) { 61 | if (model.hasToJsonMethod()) { 62 | writer.println("(defn to-json [^" + className + " " + kebabCaseObjName + "]"); 63 | writer.println(" (.toJson " + kebabCaseObjName + "))"); 64 | } 65 | } 66 | 67 | private void renderProperty(CodeWriter writer, String className, String kebabCaseObjName, String propName, PropertyInfo propertyInfo) { 68 | String prop = clojurifyName(propName); 69 | if (propertyInfo.isAdder()) { 70 | String adderMethod = propertyInfo.getAdderMethod(); 71 | if (propertyInfo.isMap()) { 72 | writer.println("(defn " + clojurifyName(adderMethod) 73 | + " [^" + className + " " + kebabCaseObjName + " key val]"); 74 | writer.println(" (." + adderMethod + " " + kebabCaseObjName + " key val))"); 75 | } else { 76 | writer.println("(defn " + clojurifyName(adderMethod) 77 | + " [^" + className + " " + kebabCaseObjName + " " + prop + "]"); 78 | writer.println(" (." + adderMethod + " " + kebabCaseObjName + " " + prop + "))"); 79 | } 80 | } 81 | 82 | if (propertyInfo.isSetter()) { 83 | String setterMethod = propertyInfo.getSetterMethod(); 84 | writer.println("(defn " + clojurifyName(setterMethod) 85 | + "[^" + className + " " + kebabCaseObjName + " " + prop + "]"); 86 | writer.println(" (." + setterMethod + " " + kebabCaseObjName + " " + prop + "))"); 87 | } 88 | 89 | if (propertyInfo.getGetterMethod() != null) { 90 | String getterMethod = propertyInfo.getGetterMethod(); 91 | writer.println("(defn " + clojurifyName(getterMethod) 92 | + "[^" + className + " " + kebabCaseObjName + "]"); 93 | writer.println(" (." + getterMethod + " " + kebabCaseObjName + "))"); 94 | } 95 | writer.println(); 96 | } 97 | 98 | private void renderImport(DataObjectModel model, CodeWriter writer) { 99 | writer.println("(import io.vertx.core.json.JsonObject)"); 100 | writer.println("(import " + model.getType().getRaw() + ")"); 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/src/main/java/io/vertx/lang/clojure/ClojureGeneratorLoader.java: -------------------------------------------------------------------------------- 1 | package io.vertx.lang.clojure; 2 | 3 | import io.vertx.codegen.Generator; 4 | import io.vertx.codegen.GeneratorLoader; 5 | 6 | import javax.annotation.processing.ProcessingEnvironment; 7 | import java.util.stream.Stream; 8 | 9 | public class ClojureGeneratorLoader implements GeneratorLoader { 10 | 11 | @Override 12 | public Stream> loadGenerators(ProcessingEnvironment processingEnv) { 13 | return Stream.of(new ClojureDataObjectGenerator(), new ClojureClassGenerator()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/src/main/java/io/vertx/lang/clojure/utils/ClojureUtils.java: -------------------------------------------------------------------------------- 1 | package io.vertx.lang.clojure.utils; 2 | 3 | import io.vertx.codegen.format.CamelCase; 4 | import io.vertx.codegen.format.Case; 5 | import io.vertx.codegen.format.KebabCase; 6 | 7 | public final class ClojureUtils { 8 | 9 | private final static Case KEBAB_CASE = KebabCase.INSTANCE; 10 | private final static Case CAMEL_CASE = CamelCase.INSTANCE; 11 | 12 | public static String clojurifyName(String name) { 13 | return KEBAB_CASE.format(CAMEL_CASE.parse(name)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vertx-lang-clojure-gen/src/main/resources/META-INF/services/io.vertx.codegen.GeneratorLoader: -------------------------------------------------------------------------------- 1 | io.vertx.lang.clojure.ClojureGeneratorLoader 2 | -------------------------------------------------------------------------------- /vertx-lang-clojure/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | com.sparcing 8 | vertx-lang-clojure-parent 9 | 4.5.7 10 | 11 | 12 | 4.0.0 13 | 14 | vertx-lang-clojure 15 | 4.5.7 16 | 17 | 18 | 1.2.17 19 | 1.7.21 20 | 2.8.2 21 | 22 | 23 | 24 | 25 | org.clojure 26 | clojure 27 | provided 28 | 29 | 30 | io.vertx 31 | vertx-codegen 32 | 4.5.7 33 | provided 34 | 35 | 36 | io.vertx 37 | vertx-docgen 38 | true 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | io.vertx 47 | vertx-core 48 | 49 | 50 | io.vertx 51 | vertx-web-common 52 | true 53 | 54 | 55 | io.vertx 56 | vertx-web-client 57 | true 58 | 59 | 60 | io.vertx 61 | vertx-web 62 | true 63 | 64 | 65 | io.vertx 66 | vertx-auth-common 67 | true 68 | 69 | 70 | io.vertx 71 | vertx-auth-jdbc 72 | true 73 | 74 | 75 | io.vertx 76 | vertx-auth-htdigest 77 | true 78 | 79 | 80 | io.vertx 81 | vertx-auth-htpasswd 82 | true 83 | 84 | 85 | io.vertx 86 | vertx-auth-jwt 87 | true 88 | 89 | 90 | io.vertx 91 | vertx-auth-mongo 92 | true 93 | 94 | 95 | io.vertx 96 | vertx-auth-oauth2 97 | true 98 | 99 | 100 | io.vertx 101 | vertx-auth-shiro 102 | true 103 | 104 | 105 | io.vertx 106 | vertx-auth-webauthn 107 | true 108 | 109 | 110 | io.vertx 111 | vertx-config 112 | true 113 | 114 | 115 | io.vertx 116 | vertx-jdbc-client 117 | true 118 | 119 | 120 | 121 | log4j 122 | log4j 123 | ${log4j.version} 124 | provided 125 | 126 | 127 | org.apache.logging.log4j 128 | log4j-api 129 | ${log4j2.version} 130 | provided 131 | 132 | 133 | org.apache.logging.log4j 134 | log4j-core 135 | ${log4j2.version} 136 | provided 137 | 138 | 139 | org.slf4j 140 | slf4j-api 141 | ${slf4j.version} 142 | provided 143 | 144 | 145 | org.mvel 146 | mvel2 147 | 2.2.6.Final 148 | provided 149 | 150 | 151 | com.fasterxml.jackson.core 152 | jackson-databind 153 | 2.9.9.1 154 | 155 | 156 | 157 | 158 | io.vertx 159 | vertx-codegen 160 | tck 161 | test 162 | 163 | 164 | io.vertx 165 | vertx-codegen 166 | tck-sources 167 | test 168 | 169 | 170 | io.vertx 171 | vertx-codegen 172 | sources 173 | test 174 | 175 | 176 | junit 177 | junit 178 | 4.12 179 | test 180 | 181 | 182 | io.vertx 183 | vertx-core 184 | test-jar 185 | test 186 | 187 | 188 | 189 | io.netty 190 | netty-transport-native-epoll 191 | true 192 | 193 | 194 | io.netty 195 | netty-transport-native-kqueue 196 | true 197 | 198 | 199 | com.weblogism 200 | vertx-lang-clojure-gen 201 | 4.1.0-SNAPSHOT 202 | true 203 | 204 | 205 | 206 | clojure 207 | 208 | 209 | 210 | 211 | maven-dependency-plugin 212 | 213 | io.vertx 214 | false 215 | 216 | 217 | 218 | 219 | unpack-vertx-core 220 | generate-sources 221 | 222 | unpack-dependencies 223 | 224 | 225 | 226 | vertx-core, 227 | vertx-unit, 228 | vertx-bridge-common, 229 | vertx-sql-common, 230 | vertx-mongo-client, 231 | vertx-cassandra-client, 232 | vertx-jdbc-client, 233 | vertx-auth-common, 234 | vertx-auth-jdbc, 235 | vertx-auth-htdigest, 236 | vertx-auth-htpasswd, 237 | vertx-auth-jwt, 238 | vertx-auth-mongo, 239 | vertx-auth-oauth2, 240 | vertx-auth-shiro, 241 | vertx-auth-webauthn, 242 | vertx-web-common, 243 | vertx-web-client, 244 | vertx-web, 245 | vertx-config 246 | 247 | sources 248 | 249 | **/impl/**/*.java,io/vertx/ext/web/handler/OtpAuthHandler.java,examples/**,io/vertx/groovy/**,io/vertx/reactivex/**,io/vertx/rxjava/**,examples/override/**,io/vertx/codegen/testmodel/**,io/vertx/ext/auth/AuthOptions.java 250 | ${project.build.directory}/sources/vertx-core 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | org.bsc.maven 271 | maven-processor-plugin 272 | 273 | 274 | 275 | generate-vertx-core 276 | 277 | process 278 | 279 | generate-sources 280 | 281 | 282 | %4$s: %3$s - %5$s %6$s%n 283 | 284 | 285 | io.vertx.codegen.CodeGenProcessor 286 | 287 | 288 | ${project.basedir}/src/main 289 | 290 | ${project.build.directory}/sources/vertx-core 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | docgen-docs 317 | 318 | process 319 | 320 | prepare-package 321 | 322 | 323 | io.vertx.docgen.DocGenProcessor 324 | 325 | 326 | ${asciidoc.dir}/clojure 327 | ${project.groupId} 328 | ${project.artifactId} 329 | ${project.version} 330 | 331 | ${project.build.directory}/sources/vertx-core 332 | 333 | 334 | 335 | 336 | 337 | generate-docoverride 338 | 339 | process 340 | 341 | prepare-package 342 | 343 | 344 | io.vertx.docgen.DocGenProcessor 345 | 346 | 347 | ${asciidoc.dir}/clojure 348 | ${project.groupId} 349 | ${project.artifactId} 350 | ${project.version} 351 | 352 | src/main/docoverride 353 | 354 | 355 | 356 | 357 | 358 | junit 359 | junit 360 | ${junit.version} 361 | 362 | 363 | 364 | 365 | com.theoryinpractise 366 | clojure-maven-plugin 367 | ${clojure.plugin.version} 368 | true 369 | 370 | 371 | !.* 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | docs 382 | 383 | 384 | 385 | org.asciidoctor 386 | asciidoctor-maven-plugin 387 | 388 | 389 | 390 | process-asciidoc 391 | 392 | prepare-package 393 | 394 | 395 | 396 | 397 | maven-javadoc-plugin 398 | 399 | 400 | 401 | ${project.build.directory}/sources/vertx-core/ 402 | ${project.build.directory}/docs 403 | 404 | package 405 | 406 | javadoc 407 | jar 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | -------------------------------------------------------------------------------- /vertx-lang-clojure/src/main/asciidoc/clojure/buffers.adoc: -------------------------------------------------------------------------------- 1 | == Buffers 2 | :toc: left 3 | 4 | Most data is shuffled around inside Vert.x using buffers. 5 | 6 | A buffer is a sequence of zero or more bytes that can read from or written to and which expands automatically as 7 | necessary to accommodate any bytes written to it. You can perhaps think of a buffer as smart byte array. 8 | 9 | === Creating buffers 10 | 11 | Buffers can create by using one of the static `link:../../apidocs/io/vertx/core/buffer/Buffer.html#buffer--[Buffer.buffer]` methods. 12 | 13 | Buffers can be initialised from strings or byte arrays, or empty buffers can be created. 14 | 15 | Here are some examples of creating buffers: 16 | 17 | Create a new empty buffer: 18 | 19 | [source,clojure] 20 | ---- 21 | /* 22 | * Copyright (c) 2014 Red Hat, Inc. and others 23 | * 24 | * This program and the accompanying materials are made available under the 25 | * terms of the Eclipse Public License 2.0 which is available at 26 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 27 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 28 | * 29 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 30 | */ 31 | 32 | package examples; 33 | 34 | import io.vertx.core.buffer.Buffer; 35 | import io.vertx.core.net.NetSocket; 36 | 37 | /** 38 | * Created by tim on 09/01/15. 39 | */ 40 | public class BufferExamples { 41 | 42 | public void example1() { 43 | Buffer buff = Buffer.buffer(); 44 | } 45 | 46 | public void example2() { 47 | Buffer buff = Buffer.buffer("some string"); 48 | } 49 | 50 | public void example3() { 51 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 52 | } 53 | 54 | public void example5() { 55 | Buffer buff = Buffer.buffer(10000); 56 | } 57 | 58 | public void example6(NetSocket socket) { 59 | Buffer buff = Buffer.buffer(); 60 | 61 | buff.appendInt(123).appendString("hello\n"); 62 | 63 | socket.write(buff); 64 | } 65 | 66 | public void example7() { 67 | Buffer buff = Buffer.buffer(); 68 | 69 | buff.setInt(1000, 123); 70 | buff.setString(0, "hello"); 71 | } 72 | 73 | public void example8() { 74 | Buffer buff = Buffer.buffer(); 75 | for (int i = 0; i < buff.length(); i += 4) { 76 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 77 | } 78 | } 79 | 80 | public void example9() { 81 | Buffer buff = Buffer.buffer(128); 82 | int pos = 15; 83 | buff.setUnsignedByte(pos, (short) 200); 84 | System.out.println(buff.getUnsignedByte(pos)); 85 | } 86 | 87 | } 88 | 89 | ---- 90 | 91 | Create a buffer from a String. The String will be encoded in the buffer using UTF-8. 92 | 93 | [source,clojure] 94 | ---- 95 | /* 96 | * Copyright (c) 2014 Red Hat, Inc. and others 97 | * 98 | * This program and the accompanying materials are made available under the 99 | * terms of the Eclipse Public License 2.0 which is available at 100 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 101 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 102 | * 103 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 104 | */ 105 | 106 | package examples; 107 | 108 | import io.vertx.core.buffer.Buffer; 109 | import io.vertx.core.net.NetSocket; 110 | 111 | /** 112 | * Created by tim on 09/01/15. 113 | */ 114 | public class BufferExamples { 115 | 116 | public void example1() { 117 | Buffer buff = Buffer.buffer(); 118 | } 119 | 120 | public void example2() { 121 | Buffer buff = Buffer.buffer("some string"); 122 | } 123 | 124 | public void example3() { 125 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 126 | } 127 | 128 | public void example5() { 129 | Buffer buff = Buffer.buffer(10000); 130 | } 131 | 132 | public void example6(NetSocket socket) { 133 | Buffer buff = Buffer.buffer(); 134 | 135 | buff.appendInt(123).appendString("hello\n"); 136 | 137 | socket.write(buff); 138 | } 139 | 140 | public void example7() { 141 | Buffer buff = Buffer.buffer(); 142 | 143 | buff.setInt(1000, 123); 144 | buff.setString(0, "hello"); 145 | } 146 | 147 | public void example8() { 148 | Buffer buff = Buffer.buffer(); 149 | for (int i = 0; i < buff.length(); i += 4) { 150 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 151 | } 152 | } 153 | 154 | public void example9() { 155 | Buffer buff = Buffer.buffer(128); 156 | int pos = 15; 157 | buff.setUnsignedByte(pos, (short) 200); 158 | System.out.println(buff.getUnsignedByte(pos)); 159 | } 160 | 161 | } 162 | 163 | ---- 164 | 165 | Create a buffer from a String: The String will be encoded using the specified encoding, e.g: 166 | 167 | [source,clojure] 168 | ---- 169 | /* 170 | * Copyright (c) 2014 Red Hat, Inc. and others 171 | * 172 | * This program and the accompanying materials are made available under the 173 | * terms of the Eclipse Public License 2.0 which is available at 174 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 175 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 176 | * 177 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 178 | */ 179 | 180 | package examples; 181 | 182 | import io.vertx.core.buffer.Buffer; 183 | import io.vertx.core.net.NetSocket; 184 | 185 | /** 186 | * Created by tim on 09/01/15. 187 | */ 188 | public class BufferExamples { 189 | 190 | public void example1() { 191 | Buffer buff = Buffer.buffer(); 192 | } 193 | 194 | public void example2() { 195 | Buffer buff = Buffer.buffer("some string"); 196 | } 197 | 198 | public void example3() { 199 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 200 | } 201 | 202 | public void example5() { 203 | Buffer buff = Buffer.buffer(10000); 204 | } 205 | 206 | public void example6(NetSocket socket) { 207 | Buffer buff = Buffer.buffer(); 208 | 209 | buff.appendInt(123).appendString("hello\n"); 210 | 211 | socket.write(buff); 212 | } 213 | 214 | public void example7() { 215 | Buffer buff = Buffer.buffer(); 216 | 217 | buff.setInt(1000, 123); 218 | buff.setString(0, "hello"); 219 | } 220 | 221 | public void example8() { 222 | Buffer buff = Buffer.buffer(); 223 | for (int i = 0; i < buff.length(); i += 4) { 224 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 225 | } 226 | } 227 | 228 | public void example9() { 229 | Buffer buff = Buffer.buffer(128); 230 | int pos = 15; 231 | buff.setUnsignedByte(pos, (short) 200); 232 | System.out.println(buff.getUnsignedByte(pos)); 233 | } 234 | 235 | } 236 | 237 | ---- 238 | 239 | include::override/buffer_from_bytes.adoc[] 240 | 241 | Create a buffer with an initial size hint. If you know your buffer will have a certain amount of data written to it 242 | you can create the buffer and specify this size. This makes the buffer initially allocate that much memory and is 243 | more efficient than the buffer automatically resizing multiple times as data is written to it. 244 | 245 | Note that buffers created this way *are empty*. It does not create a buffer filled with zeros up to the specified size. 246 | 247 | [source,clojure] 248 | ---- 249 | /* 250 | * Copyright (c) 2014 Red Hat, Inc. and others 251 | * 252 | * This program and the accompanying materials are made available under the 253 | * terms of the Eclipse Public License 2.0 which is available at 254 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 255 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 256 | * 257 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 258 | */ 259 | 260 | package examples; 261 | 262 | import io.vertx.core.buffer.Buffer; 263 | import io.vertx.core.net.NetSocket; 264 | 265 | /** 266 | * Created by tim on 09/01/15. 267 | */ 268 | public class BufferExamples { 269 | 270 | public void example1() { 271 | Buffer buff = Buffer.buffer(); 272 | } 273 | 274 | public void example2() { 275 | Buffer buff = Buffer.buffer("some string"); 276 | } 277 | 278 | public void example3() { 279 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 280 | } 281 | 282 | public void example5() { 283 | Buffer buff = Buffer.buffer(10000); 284 | } 285 | 286 | public void example6(NetSocket socket) { 287 | Buffer buff = Buffer.buffer(); 288 | 289 | buff.appendInt(123).appendString("hello\n"); 290 | 291 | socket.write(buff); 292 | } 293 | 294 | public void example7() { 295 | Buffer buff = Buffer.buffer(); 296 | 297 | buff.setInt(1000, 123); 298 | buff.setString(0, "hello"); 299 | } 300 | 301 | public void example8() { 302 | Buffer buff = Buffer.buffer(); 303 | for (int i = 0; i < buff.length(); i += 4) { 304 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 305 | } 306 | } 307 | 308 | public void example9() { 309 | Buffer buff = Buffer.buffer(128); 310 | int pos = 15; 311 | buff.setUnsignedByte(pos, (short) 200); 312 | System.out.println(buff.getUnsignedByte(pos)); 313 | } 314 | 315 | } 316 | 317 | ---- 318 | 319 | === Writing to a Buffer 320 | 321 | There are two ways to write to a buffer: appending, and random access. 322 | In either case buffers will always expand automatically to encompass the bytes. It's not possible to get 323 | an `IndexOutOfBoundsException` with a buffer. 324 | 325 | ==== Appending to a Buffer 326 | 327 | To append to a buffer, you use the `appendXXX` methods. 328 | Append methods exist for appending various different types. 329 | 330 | The return value of the `appendXXX` methods is the buffer itself, so these can be chained: 331 | 332 | [source,clojure] 333 | ---- 334 | /* 335 | * Copyright (c) 2014 Red Hat, Inc. and others 336 | * 337 | * This program and the accompanying materials are made available under the 338 | * terms of the Eclipse Public License 2.0 which is available at 339 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 340 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 341 | * 342 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 343 | */ 344 | 345 | package examples; 346 | 347 | import io.vertx.core.buffer.Buffer; 348 | import io.vertx.core.net.NetSocket; 349 | 350 | /** 351 | * Created by tim on 09/01/15. 352 | */ 353 | public class BufferExamples { 354 | 355 | public void example1() { 356 | Buffer buff = Buffer.buffer(); 357 | } 358 | 359 | public void example2() { 360 | Buffer buff = Buffer.buffer("some string"); 361 | } 362 | 363 | public void example3() { 364 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 365 | } 366 | 367 | public void example5() { 368 | Buffer buff = Buffer.buffer(10000); 369 | } 370 | 371 | public void example6(NetSocket socket) { 372 | Buffer buff = Buffer.buffer(); 373 | 374 | buff.appendInt(123).appendString("hello\n"); 375 | 376 | socket.write(buff); 377 | } 378 | 379 | public void example7() { 380 | Buffer buff = Buffer.buffer(); 381 | 382 | buff.setInt(1000, 123); 383 | buff.setString(0, "hello"); 384 | } 385 | 386 | public void example8() { 387 | Buffer buff = Buffer.buffer(); 388 | for (int i = 0; i < buff.length(); i += 4) { 389 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 390 | } 391 | } 392 | 393 | public void example9() { 394 | Buffer buff = Buffer.buffer(128); 395 | int pos = 15; 396 | buff.setUnsignedByte(pos, (short) 200); 397 | System.out.println(buff.getUnsignedByte(pos)); 398 | } 399 | 400 | } 401 | 402 | ---- 403 | 404 | ==== Random access buffer writes 405 | 406 | You can also write into the buffer at a specific index, by using the `setXXX` methods. 407 | Set methods exist for various different data types. All the set methods take an index as the first argument - this 408 | represents the position in the buffer where to start writing the data. 409 | 410 | The buffer will always expand as necessary to accommodate the data. 411 | 412 | [source,clojure] 413 | ---- 414 | /* 415 | * Copyright (c) 2014 Red Hat, Inc. and others 416 | * 417 | * This program and the accompanying materials are made available under the 418 | * terms of the Eclipse Public License 2.0 which is available at 419 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 420 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 421 | * 422 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 423 | */ 424 | 425 | package examples; 426 | 427 | import io.vertx.core.buffer.Buffer; 428 | import io.vertx.core.net.NetSocket; 429 | 430 | /** 431 | * Created by tim on 09/01/15. 432 | */ 433 | public class BufferExamples { 434 | 435 | public void example1() { 436 | Buffer buff = Buffer.buffer(); 437 | } 438 | 439 | public void example2() { 440 | Buffer buff = Buffer.buffer("some string"); 441 | } 442 | 443 | public void example3() { 444 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 445 | } 446 | 447 | public void example5() { 448 | Buffer buff = Buffer.buffer(10000); 449 | } 450 | 451 | public void example6(NetSocket socket) { 452 | Buffer buff = Buffer.buffer(); 453 | 454 | buff.appendInt(123).appendString("hello\n"); 455 | 456 | socket.write(buff); 457 | } 458 | 459 | public void example7() { 460 | Buffer buff = Buffer.buffer(); 461 | 462 | buff.setInt(1000, 123); 463 | buff.setString(0, "hello"); 464 | } 465 | 466 | public void example8() { 467 | Buffer buff = Buffer.buffer(); 468 | for (int i = 0; i < buff.length(); i += 4) { 469 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 470 | } 471 | } 472 | 473 | public void example9() { 474 | Buffer buff = Buffer.buffer(128); 475 | int pos = 15; 476 | buff.setUnsignedByte(pos, (short) 200); 477 | System.out.println(buff.getUnsignedByte(pos)); 478 | } 479 | 480 | } 481 | 482 | ---- 483 | 484 | === Reading from a Buffer 485 | 486 | Data is read from a buffer using the `getXXX` methods. Get methods exist for various datatypes. 487 | The first argument to these methods is an index in the buffer from where to get the data. 488 | 489 | [source,clojure] 490 | ---- 491 | /* 492 | * Copyright (c) 2014 Red Hat, Inc. and others 493 | * 494 | * This program and the accompanying materials are made available under the 495 | * terms of the Eclipse Public License 2.0 which is available at 496 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 497 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 498 | * 499 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 500 | */ 501 | 502 | package examples; 503 | 504 | import io.vertx.core.buffer.Buffer; 505 | import io.vertx.core.net.NetSocket; 506 | 507 | /** 508 | * Created by tim on 09/01/15. 509 | */ 510 | public class BufferExamples { 511 | 512 | public void example1() { 513 | Buffer buff = Buffer.buffer(); 514 | } 515 | 516 | public void example2() { 517 | Buffer buff = Buffer.buffer("some string"); 518 | } 519 | 520 | public void example3() { 521 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 522 | } 523 | 524 | public void example5() { 525 | Buffer buff = Buffer.buffer(10000); 526 | } 527 | 528 | public void example6(NetSocket socket) { 529 | Buffer buff = Buffer.buffer(); 530 | 531 | buff.appendInt(123).appendString("hello\n"); 532 | 533 | socket.write(buff); 534 | } 535 | 536 | public void example7() { 537 | Buffer buff = Buffer.buffer(); 538 | 539 | buff.setInt(1000, 123); 540 | buff.setString(0, "hello"); 541 | } 542 | 543 | public void example8() { 544 | Buffer buff = Buffer.buffer(); 545 | for (int i = 0; i < buff.length(); i += 4) { 546 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 547 | } 548 | } 549 | 550 | public void example9() { 551 | Buffer buff = Buffer.buffer(128); 552 | int pos = 15; 553 | buff.setUnsignedByte(pos, (short) 200); 554 | System.out.println(buff.getUnsignedByte(pos)); 555 | } 556 | 557 | } 558 | 559 | ---- 560 | 561 | === Working with unsigned numbers 562 | 563 | Unsigned numbers can be read from or appended/set to a buffer with the `getUnsignedXXX`, 564 | `appendUnsignedXXX` and `setUnsignedXXX` methods. This is useful when implementing a codec for a 565 | network protocol optimized to minimize bandwidth consumption. 566 | 567 | In the following example, value 200 is set at specified position with just one byte: 568 | 569 | [source,clojure] 570 | ---- 571 | /* 572 | * Copyright (c) 2014 Red Hat, Inc. and others 573 | * 574 | * This program and the accompanying materials are made available under the 575 | * terms of the Eclipse Public License 2.0 which is available at 576 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 577 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 578 | * 579 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 580 | */ 581 | 582 | package examples; 583 | 584 | import io.vertx.core.buffer.Buffer; 585 | import io.vertx.core.net.NetSocket; 586 | 587 | /** 588 | * Created by tim on 09/01/15. 589 | */ 590 | public class BufferExamples { 591 | 592 | public void example1() { 593 | Buffer buff = Buffer.buffer(); 594 | } 595 | 596 | public void example2() { 597 | Buffer buff = Buffer.buffer("some string"); 598 | } 599 | 600 | public void example3() { 601 | Buffer buff = Buffer.buffer("some string", "UTF-16"); 602 | } 603 | 604 | public void example5() { 605 | Buffer buff = Buffer.buffer(10000); 606 | } 607 | 608 | public void example6(NetSocket socket) { 609 | Buffer buff = Buffer.buffer(); 610 | 611 | buff.appendInt(123).appendString("hello\n"); 612 | 613 | socket.write(buff); 614 | } 615 | 616 | public void example7() { 617 | Buffer buff = Buffer.buffer(); 618 | 619 | buff.setInt(1000, 123); 620 | buff.setString(0, "hello"); 621 | } 622 | 623 | public void example8() { 624 | Buffer buff = Buffer.buffer(); 625 | for (int i = 0; i < buff.length(); i += 4) { 626 | System.out.println("int value at " + i + " is " + buff.getInt(i)); 627 | } 628 | } 629 | 630 | public void example9() { 631 | Buffer buff = Buffer.buffer(128); 632 | int pos = 15; 633 | buff.setUnsignedByte(pos, (short) 200); 634 | System.out.println(buff.getUnsignedByte(pos)); 635 | } 636 | 637 | } 638 | 639 | ---- 640 | 641 | The console shows '200'. 642 | 643 | === Buffer length 644 | 645 | Use `link:../../apidocs/io/vertx/core/buffer/Buffer.html#length--[length]` to obtain the length of the buffer. 646 | The length of a buffer is the index of the byte in the buffer with the largest index + 1. 647 | 648 | === Copying buffers 649 | 650 | Use `link:../../apidocs/io/vertx/core/buffer/Buffer.html#copy--[copy]` to make a copy of the buffer 651 | 652 | === Slicing buffers 653 | 654 | A sliced buffer is a new buffer which backs onto the original buffer, i.e. it does not copy the underlying data. 655 | Use `link:../../apidocs/io/vertx/core/buffer/Buffer.html#slice--[slice]` to create a sliced buffers 656 | 657 | === Buffer re-use 658 | 659 | After writing a buffer to a socket or other similar place, they cannot be re-used. -------------------------------------------------------------------------------- /vertx-lang-clojure/src/main/asciidoc/clojure/cli-for-java.adoc: -------------------------------------------------------------------------------- 1 | === Typed options and arguments 2 | 3 | The described `link:../../apidocs/io/vertx/core/cli/Option.html[Option]` and `link:../../apidocs/io/vertx/core/cli/Argument.html[Argument]` classes are _untyped_, 4 | meaning that the only get String values. 5 | 6 | `link:../../apidocs/io/vertx/core/cli/TypedOption.html[TypedOption]` and `link:../../apidocs/io/vertx/core/cli/TypedArgument.html[TypedArgument]` let you specify a _type_, so the 7 | (String) raw value is converted to the specified type. 8 | 9 | Instead of 10 | `link:../../apidocs/io/vertx/core/cli/Option.html[Option]` and `link:../../apidocs/io/vertx/core/cli/Argument.html[Argument]`, use `link:../../apidocs/io/vertx/core/cli/TypedOption.html[TypedOption]` 11 | and `link:../../apidocs/io/vertx/core/cli/TypedArgument.html[TypedArgument]` in the `link:../../apidocs/io/vertx/core/cli/CLI.html[CLI]` definition: 12 | 13 | [source,java] 14 | ---- 15 | CLI cli = CLI.create("copy") 16 | .setSummary("A command line interface to copy files.") 17 | .addOption(new TypedOption() 18 | .setType(Boolean.class) 19 | .setLongName("directory") 20 | .setShortName("R") 21 | .setDescription("enables directory support") 22 | .setFlag(true)) 23 | .addArgument(new TypedArgument() 24 | .setType(File.class) 25 | .setIndex(0) 26 | .setDescription("The source") 27 | .setArgName("source")) 28 | .addArgument(new TypedArgument() 29 | .setType(File.class) 30 | .setIndex(0) 31 | .setDescription("The destination") 32 | .setArgName("target")); 33 | ---- 34 | 35 | Then you can retrieve the converted values as follows: 36 | 37 | [source,java] 38 | ---- 39 | CommandLine commandLine = cli.parse(userCommandLineArguments); 40 | boolean flag = commandLine.getOptionValue("R"); 41 | File source = commandLine.getArgumentValue("source"); 42 | File target = commandLine.getArgumentValue("target"); 43 | ---- 44 | 45 | The vert.x CLI is able to convert to classes: 46 | 47 | * having a constructor with a single 48 | `link:../../apidocs/java/lang/String.html[String]` argument, such as `link:../../apidocs/java/io/File.html[File]` or `link:../../apidocs/io/vertx/core/json/JsonObject.html[JsonObject]` 49 | * with a static `from` or `fromString` method 50 | * with a static `valueOf` method, such as primitive types and enumeration 51 | 52 | In addition, you can implement your own `link:../../apidocs/io/vertx/core/cli/converters/Converter.html[Converter]` and instruct the CLI to use 53 | this converter: 54 | 55 | [source,java] 56 | ---- 57 | CLI cli = CLI.create("some-name") 58 | .addOption(new TypedOption() 59 | .setType(Person.class) 60 | .setConverter(new PersonConverter()) 61 | .setLongName("person")); 62 | ---- 63 | 64 | For booleans, the boolean values are evaluated to `true`: `on`, `yes`, `1`, `true`. 65 | 66 | If one of your option has an `enum` as type, it computes the set of choices automatically. 67 | 68 | === Using annotations 69 | 70 | You can also define your CLI using annotations. Definition is done using annotation on the class and on _setter_ 71 | methods: 72 | 73 | [source, java] 74 | ---- 75 | @Name("some-name") 76 | @Summary("some short summary.") 77 | @Description("some long description") 78 | public class AnnotatedCli { 79 | 80 | private boolean flag; 81 | private String name; 82 | private String arg; 83 | 84 | @Option(shortName = "f", flag = true) 85 | public void setFlag(boolean flag) { 86 | this.flag = flag; 87 | } 88 | 89 | @Option(longName = "name") 90 | public void setName(String name) { 91 | this.name = name; 92 | } 93 | 94 | @Argument(index = 0) 95 | public void setArg(String arg) { 96 | this.arg = arg; 97 | } 98 | } 99 | ---- 100 | 101 | Once annotated, you can define the `link:../../apidocs/io/vertx/core/cli/CLI.html[CLI]` and inject the values using: 102 | 103 | [source,java] 104 | ---- 105 | CLI cli = CLI.create(AnnotatedCli.class); 106 | CommandLine commandLine = cli.parse(userCommandLineArguments); 107 | AnnotatedCli instance = new AnnotatedCli(); 108 | CLIConfigurator.inject(commandLine, instance); 109 | ---- -------------------------------------------------------------------------------- /vertx-lang-clojure/src/main/asciidoc/clojure/datagrams.adoc: -------------------------------------------------------------------------------- 1 | == Datagram sockets (UDP) 2 | 3 | Using User Datagram Protocol (UDP) with Vert.x is a piece of cake. 4 | 5 | UDP is a connection-less transport which basically means you have no persistent connection to a remote peer. 6 | 7 | Instead you can send and receive packages and the remote address is contained in each of them. 8 | 9 | Beside this UDP is not as safe as TCP to use, which means there are no guarantees that a send Datagram packet will 10 | receive it's endpoint at all. 11 | 12 | The only guarantee is that it will either receive complete or not at all. 13 | 14 | Also you usually can't send data which is bigger then the MTU size of your network interface, this is because each 15 | packet will be send as one packet. 16 | 17 | But be aware even if the packet size is smaller then the MTU it may still fail. 18 | 19 | At which size it will fail depends on the Operating System etc. So rule of thumb is to try to send small packets. 20 | 21 | Because of the nature of UDP it is best fit for Applications where you are allowed to drop packets (like for 22 | example a monitoring application). 23 | 24 | The benefits are that it has a lot less overhead compared to TCP, which can be handled by the NetServer 25 | and NetClient (see above). 26 | 27 | === Creating a DatagramSocket 28 | 29 | To use UDP you first need t create a `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]`. It does not matter here if you only want to send data or send 30 | and receive. 31 | 32 | [source,clojure] 33 | ---- 34 | /* 35 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 36 | * 37 | * This program and the accompanying materials are made available under the 38 | * terms of the Eclipse Public License 2.0 which is available at 39 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 40 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 41 | * 42 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 43 | */ 44 | 45 | package examples; 46 | 47 | import io.vertx.core.Vertx; 48 | import io.vertx.core.buffer.Buffer; 49 | import io.vertx.core.datagram.DatagramSocket; 50 | import io.vertx.core.datagram.DatagramSocketOptions; 51 | 52 | /** 53 | * @author Julien Viet 54 | */ 55 | public class DatagramExamples { 56 | 57 | public void example1(Vertx vertx) { 58 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 59 | } 60 | 61 | public void example2(Vertx vertx) { 62 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 63 | Buffer buffer = Buffer.buffer("content"); 64 | // Send a Buffer 65 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 66 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 67 | }); 68 | // Send a String 69 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 70 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 71 | }); 72 | } 73 | 74 | public void example3(Vertx vertx) { 75 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 76 | socket.listen(1234, "0.0.0.0", asyncResult -> { 77 | if (asyncResult.succeeded()) { 78 | socket.handler(packet -> { 79 | // Do something with the packet 80 | }); 81 | } else { 82 | System.out.println("Listen failed" + asyncResult.cause()); 83 | } 84 | }); 85 | } 86 | 87 | public void example4(Vertx vertx) { 88 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 89 | Buffer buffer = Buffer.buffer("content"); 90 | // Send a Buffer to a multicast address 91 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 92 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 93 | }); 94 | } 95 | 96 | public void example5(Vertx vertx) { 97 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 98 | socket.listen(1234, "0.0.0.0", asyncResult -> { 99 | if (asyncResult.succeeded()) { 100 | socket.handler(packet -> { 101 | // Do something with the packet 102 | }); 103 | 104 | // join the multicast group 105 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 106 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 107 | }); 108 | } else { 109 | System.out.println("Listen failed" + asyncResult.cause()); 110 | } 111 | }); 112 | } 113 | 114 | public void example6(Vertx vertx) { 115 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 116 | socket.listen(1234, "0.0.0.0", asyncResult -> { 117 | if (asyncResult.succeeded()) { 118 | socket.handler(packet -> { 119 | // Do something with the packet 120 | }); 121 | 122 | // join the multicast group 123 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 124 | if (asyncResult2.succeeded()) { 125 | // will now receive packets for group 126 | 127 | // do some work 128 | 129 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 130 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 131 | }); 132 | } else { 133 | System.out.println("Listen failed" + asyncResult2.cause()); 134 | } 135 | }); 136 | } else { 137 | System.out.println("Listen failed" + asyncResult.cause()); 138 | } 139 | }); 140 | } 141 | 142 | public void example7(Vertx vertx) { 143 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 144 | 145 | // Some code 146 | 147 | // This would block packets which are send from 10.0.0.2 148 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 149 | System.out.println("block succeeded? " + asyncResult.succeeded()); 150 | }); 151 | } 152 | } 153 | 154 | ---- 155 | 156 | The returned `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` will not be bound to a specific port. This is not a 157 | problem if you only want to send data (like a client), but more on this in the next section. 158 | 159 | === Sending Datagram packets 160 | 161 | As mentioned before, User Datagram Protocol (UDP) sends data in packets to remote peers but is not connected to 162 | them in a persistent fashion. 163 | 164 | This means each packet can be sent to a different remote peer. 165 | 166 | Sending packets is as easy as shown here: 167 | 168 | [source,clojure] 169 | ---- 170 | /* 171 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 172 | * 173 | * This program and the accompanying materials are made available under the 174 | * terms of the Eclipse Public License 2.0 which is available at 175 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 176 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 177 | * 178 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 179 | */ 180 | 181 | package examples; 182 | 183 | import io.vertx.core.Vertx; 184 | import io.vertx.core.buffer.Buffer; 185 | import io.vertx.core.datagram.DatagramSocket; 186 | import io.vertx.core.datagram.DatagramSocketOptions; 187 | 188 | /** 189 | * @author Julien Viet 190 | */ 191 | public class DatagramExamples { 192 | 193 | public void example1(Vertx vertx) { 194 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 195 | } 196 | 197 | public void example2(Vertx vertx) { 198 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 199 | Buffer buffer = Buffer.buffer("content"); 200 | // Send a Buffer 201 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 202 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 203 | }); 204 | // Send a String 205 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 206 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 207 | }); 208 | } 209 | 210 | public void example3(Vertx vertx) { 211 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 212 | socket.listen(1234, "0.0.0.0", asyncResult -> { 213 | if (asyncResult.succeeded()) { 214 | socket.handler(packet -> { 215 | // Do something with the packet 216 | }); 217 | } else { 218 | System.out.println("Listen failed" + asyncResult.cause()); 219 | } 220 | }); 221 | } 222 | 223 | public void example4(Vertx vertx) { 224 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 225 | Buffer buffer = Buffer.buffer("content"); 226 | // Send a Buffer to a multicast address 227 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 228 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 229 | }); 230 | } 231 | 232 | public void example5(Vertx vertx) { 233 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 234 | socket.listen(1234, "0.0.0.0", asyncResult -> { 235 | if (asyncResult.succeeded()) { 236 | socket.handler(packet -> { 237 | // Do something with the packet 238 | }); 239 | 240 | // join the multicast group 241 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 242 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 243 | }); 244 | } else { 245 | System.out.println("Listen failed" + asyncResult.cause()); 246 | } 247 | }); 248 | } 249 | 250 | public void example6(Vertx vertx) { 251 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 252 | socket.listen(1234, "0.0.0.0", asyncResult -> { 253 | if (asyncResult.succeeded()) { 254 | socket.handler(packet -> { 255 | // Do something with the packet 256 | }); 257 | 258 | // join the multicast group 259 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 260 | if (asyncResult2.succeeded()) { 261 | // will now receive packets for group 262 | 263 | // do some work 264 | 265 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 266 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 267 | }); 268 | } else { 269 | System.out.println("Listen failed" + asyncResult2.cause()); 270 | } 271 | }); 272 | } else { 273 | System.out.println("Listen failed" + asyncResult.cause()); 274 | } 275 | }); 276 | } 277 | 278 | public void example7(Vertx vertx) { 279 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 280 | 281 | // Some code 282 | 283 | // This would block packets which are send from 10.0.0.2 284 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 285 | System.out.println("block succeeded? " + asyncResult.succeeded()); 286 | }); 287 | } 288 | } 289 | 290 | ---- 291 | 292 | === Receiving Datagram packets 293 | 294 | If you want to receive packets you need to bind the `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` by calling 295 | `listen(...)}` on it. 296 | 297 | This way you will be able to receive `link:../../apidocs/io/vertx/core/datagram/DatagramPacket.html[DatagramPacket]`s that were sent to the address and port on 298 | which the `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` listens. 299 | 300 | Beside this you also want to set a `Handler` which will be called for each received `link:../../apidocs/io/vertx/core/datagram/DatagramPacket.html[DatagramPacket]`. 301 | 302 | The `link:../../apidocs/io/vertx/core/datagram/DatagramPacket.html[DatagramPacket]` has the following methods: 303 | 304 | - `link:../../apidocs/io/vertx/core/datagram/DatagramPacket.html#sender--[sender]`: The InetSocketAddress which represent the sender of the packet 305 | - `link:../../apidocs/io/vertx/core/datagram/DatagramPacket.html#data--[data]`: The Buffer which holds the data which was received. 306 | 307 | So to listen on a specific address and port you would do something like shown here: 308 | 309 | [source,clojure] 310 | ---- 311 | /* 312 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 313 | * 314 | * This program and the accompanying materials are made available under the 315 | * terms of the Eclipse Public License 2.0 which is available at 316 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 317 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 318 | * 319 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 320 | */ 321 | 322 | package examples; 323 | 324 | import io.vertx.core.Vertx; 325 | import io.vertx.core.buffer.Buffer; 326 | import io.vertx.core.datagram.DatagramSocket; 327 | import io.vertx.core.datagram.DatagramSocketOptions; 328 | 329 | /** 330 | * @author Julien Viet 331 | */ 332 | public class DatagramExamples { 333 | 334 | public void example1(Vertx vertx) { 335 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 336 | } 337 | 338 | public void example2(Vertx vertx) { 339 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 340 | Buffer buffer = Buffer.buffer("content"); 341 | // Send a Buffer 342 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 343 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 344 | }); 345 | // Send a String 346 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 347 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 348 | }); 349 | } 350 | 351 | public void example3(Vertx vertx) { 352 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 353 | socket.listen(1234, "0.0.0.0", asyncResult -> { 354 | if (asyncResult.succeeded()) { 355 | socket.handler(packet -> { 356 | // Do something with the packet 357 | }); 358 | } else { 359 | System.out.println("Listen failed" + asyncResult.cause()); 360 | } 361 | }); 362 | } 363 | 364 | public void example4(Vertx vertx) { 365 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 366 | Buffer buffer = Buffer.buffer("content"); 367 | // Send a Buffer to a multicast address 368 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 369 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 370 | }); 371 | } 372 | 373 | public void example5(Vertx vertx) { 374 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 375 | socket.listen(1234, "0.0.0.0", asyncResult -> { 376 | if (asyncResult.succeeded()) { 377 | socket.handler(packet -> { 378 | // Do something with the packet 379 | }); 380 | 381 | // join the multicast group 382 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 383 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 384 | }); 385 | } else { 386 | System.out.println("Listen failed" + asyncResult.cause()); 387 | } 388 | }); 389 | } 390 | 391 | public void example6(Vertx vertx) { 392 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 393 | socket.listen(1234, "0.0.0.0", asyncResult -> { 394 | if (asyncResult.succeeded()) { 395 | socket.handler(packet -> { 396 | // Do something with the packet 397 | }); 398 | 399 | // join the multicast group 400 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 401 | if (asyncResult2.succeeded()) { 402 | // will now receive packets for group 403 | 404 | // do some work 405 | 406 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 407 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 408 | }); 409 | } else { 410 | System.out.println("Listen failed" + asyncResult2.cause()); 411 | } 412 | }); 413 | } else { 414 | System.out.println("Listen failed" + asyncResult.cause()); 415 | } 416 | }); 417 | } 418 | 419 | public void example7(Vertx vertx) { 420 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 421 | 422 | // Some code 423 | 424 | // This would block packets which are send from 10.0.0.2 425 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 426 | System.out.println("block succeeded? " + asyncResult.succeeded()); 427 | }); 428 | } 429 | } 430 | 431 | ---- 432 | 433 | Be aware that even if the {code AsyncResult} is successed it only means it might be written on the network 434 | stack, but gives no guarantee that it ever reached or will reach the remote peer at all. 435 | 436 | If you need such a guarantee then you want to use TCP with some handshaking logic build on top. 437 | 438 | === Multicast 439 | 440 | ==== Sending Multicast packets 441 | 442 | Multicast allows multiple sockets to receive the same packets. This works by having the sockets join the same multicast group 443 | to which you can then send packets. 444 | 445 | We will look at how you can join a Multicast Group and receive packets in the next section. 446 | 447 | Sending multicast packets is not different than sending normal Datagram packets. The difference is that you pass 448 | in a multicast group address to the send method. 449 | 450 | This is show here: 451 | 452 | [source,clojure] 453 | ---- 454 | /* 455 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 456 | * 457 | * This program and the accompanying materials are made available under the 458 | * terms of the Eclipse Public License 2.0 which is available at 459 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 460 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 461 | * 462 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 463 | */ 464 | 465 | package examples; 466 | 467 | import io.vertx.core.Vertx; 468 | import io.vertx.core.buffer.Buffer; 469 | import io.vertx.core.datagram.DatagramSocket; 470 | import io.vertx.core.datagram.DatagramSocketOptions; 471 | 472 | /** 473 | * @author Julien Viet 474 | */ 475 | public class DatagramExamples { 476 | 477 | public void example1(Vertx vertx) { 478 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 479 | } 480 | 481 | public void example2(Vertx vertx) { 482 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 483 | Buffer buffer = Buffer.buffer("content"); 484 | // Send a Buffer 485 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 486 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 487 | }); 488 | // Send a String 489 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 490 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 491 | }); 492 | } 493 | 494 | public void example3(Vertx vertx) { 495 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 496 | socket.listen(1234, "0.0.0.0", asyncResult -> { 497 | if (asyncResult.succeeded()) { 498 | socket.handler(packet -> { 499 | // Do something with the packet 500 | }); 501 | } else { 502 | System.out.println("Listen failed" + asyncResult.cause()); 503 | } 504 | }); 505 | } 506 | 507 | public void example4(Vertx vertx) { 508 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 509 | Buffer buffer = Buffer.buffer("content"); 510 | // Send a Buffer to a multicast address 511 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 512 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 513 | }); 514 | } 515 | 516 | public void example5(Vertx vertx) { 517 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 518 | socket.listen(1234, "0.0.0.0", asyncResult -> { 519 | if (asyncResult.succeeded()) { 520 | socket.handler(packet -> { 521 | // Do something with the packet 522 | }); 523 | 524 | // join the multicast group 525 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 526 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 527 | }); 528 | } else { 529 | System.out.println("Listen failed" + asyncResult.cause()); 530 | } 531 | }); 532 | } 533 | 534 | public void example6(Vertx vertx) { 535 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 536 | socket.listen(1234, "0.0.0.0", asyncResult -> { 537 | if (asyncResult.succeeded()) { 538 | socket.handler(packet -> { 539 | // Do something with the packet 540 | }); 541 | 542 | // join the multicast group 543 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 544 | if (asyncResult2.succeeded()) { 545 | // will now receive packets for group 546 | 547 | // do some work 548 | 549 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 550 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 551 | }); 552 | } else { 553 | System.out.println("Listen failed" + asyncResult2.cause()); 554 | } 555 | }); 556 | } else { 557 | System.out.println("Listen failed" + asyncResult.cause()); 558 | } 559 | }); 560 | } 561 | 562 | public void example7(Vertx vertx) { 563 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 564 | 565 | // Some code 566 | 567 | // This would block packets which are send from 10.0.0.2 568 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 569 | System.out.println("block succeeded? " + asyncResult.succeeded()); 570 | }); 571 | } 572 | } 573 | 574 | ---- 575 | 576 | All sockets that have joined the multicast group 230.0.0.1 will receive the packet. 577 | 578 | ===== Receiving Multicast packets 579 | 580 | If you want to receive packets for specific Multicast group you need to bind the `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` by 581 | calling `listen(...)` on it to join the Multicast group. 582 | 583 | This way you will receive DatagramPackets that were sent to the address and port on which the 584 | `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` listens and also to those sent to the Multicast group. 585 | 586 | Beside this you also want to set a Handler which will be called for each received DatagramPacket. 587 | 588 | The `link:../../apidocs/io/vertx/core/datagram/DatagramPacket.html[DatagramPacket]` has the following methods: 589 | 590 | - `sender()`: The InetSocketAddress which represent the sender of the packet 591 | - `data()`: The Buffer which holds the data which was received. 592 | 593 | So to listen on a specific address and port and also receive packets for the Multicast group 230.0.0.1 you 594 | would do something like shown here: 595 | 596 | [source,clojure] 597 | ---- 598 | /* 599 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 600 | * 601 | * This program and the accompanying materials are made available under the 602 | * terms of the Eclipse Public License 2.0 which is available at 603 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 604 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 605 | * 606 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 607 | */ 608 | 609 | package examples; 610 | 611 | import io.vertx.core.Vertx; 612 | import io.vertx.core.buffer.Buffer; 613 | import io.vertx.core.datagram.DatagramSocket; 614 | import io.vertx.core.datagram.DatagramSocketOptions; 615 | 616 | /** 617 | * @author Julien Viet 618 | */ 619 | public class DatagramExamples { 620 | 621 | public void example1(Vertx vertx) { 622 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 623 | } 624 | 625 | public void example2(Vertx vertx) { 626 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 627 | Buffer buffer = Buffer.buffer("content"); 628 | // Send a Buffer 629 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 630 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 631 | }); 632 | // Send a String 633 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 634 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 635 | }); 636 | } 637 | 638 | public void example3(Vertx vertx) { 639 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 640 | socket.listen(1234, "0.0.0.0", asyncResult -> { 641 | if (asyncResult.succeeded()) { 642 | socket.handler(packet -> { 643 | // Do something with the packet 644 | }); 645 | } else { 646 | System.out.println("Listen failed" + asyncResult.cause()); 647 | } 648 | }); 649 | } 650 | 651 | public void example4(Vertx vertx) { 652 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 653 | Buffer buffer = Buffer.buffer("content"); 654 | // Send a Buffer to a multicast address 655 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 656 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 657 | }); 658 | } 659 | 660 | public void example5(Vertx vertx) { 661 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 662 | socket.listen(1234, "0.0.0.0", asyncResult -> { 663 | if (asyncResult.succeeded()) { 664 | socket.handler(packet -> { 665 | // Do something with the packet 666 | }); 667 | 668 | // join the multicast group 669 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 670 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 671 | }); 672 | } else { 673 | System.out.println("Listen failed" + asyncResult.cause()); 674 | } 675 | }); 676 | } 677 | 678 | public void example6(Vertx vertx) { 679 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 680 | socket.listen(1234, "0.0.0.0", asyncResult -> { 681 | if (asyncResult.succeeded()) { 682 | socket.handler(packet -> { 683 | // Do something with the packet 684 | }); 685 | 686 | // join the multicast group 687 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 688 | if (asyncResult2.succeeded()) { 689 | // will now receive packets for group 690 | 691 | // do some work 692 | 693 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 694 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 695 | }); 696 | } else { 697 | System.out.println("Listen failed" + asyncResult2.cause()); 698 | } 699 | }); 700 | } else { 701 | System.out.println("Listen failed" + asyncResult.cause()); 702 | } 703 | }); 704 | } 705 | 706 | public void example7(Vertx vertx) { 707 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 708 | 709 | // Some code 710 | 711 | // This would block packets which are send from 10.0.0.2 712 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 713 | System.out.println("block succeeded? " + asyncResult.succeeded()); 714 | }); 715 | } 716 | } 717 | 718 | ---- 719 | 720 | ===== Unlisten / leave a Multicast group 721 | 722 | There are sometimes situations where you want to receive packets for a Multicast group for a limited time. 723 | 724 | In this situations you can first start to listen for them and then later unlisten. 725 | 726 | This is shown here: 727 | 728 | [source,clojure] 729 | ---- 730 | /* 731 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 732 | * 733 | * This program and the accompanying materials are made available under the 734 | * terms of the Eclipse Public License 2.0 which is available at 735 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 736 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 737 | * 738 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 739 | */ 740 | 741 | package examples; 742 | 743 | import io.vertx.core.Vertx; 744 | import io.vertx.core.buffer.Buffer; 745 | import io.vertx.core.datagram.DatagramSocket; 746 | import io.vertx.core.datagram.DatagramSocketOptions; 747 | 748 | /** 749 | * @author Julien Viet 750 | */ 751 | public class DatagramExamples { 752 | 753 | public void example1(Vertx vertx) { 754 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 755 | } 756 | 757 | public void example2(Vertx vertx) { 758 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 759 | Buffer buffer = Buffer.buffer("content"); 760 | // Send a Buffer 761 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 762 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 763 | }); 764 | // Send a String 765 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 766 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 767 | }); 768 | } 769 | 770 | public void example3(Vertx vertx) { 771 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 772 | socket.listen(1234, "0.0.0.0", asyncResult -> { 773 | if (asyncResult.succeeded()) { 774 | socket.handler(packet -> { 775 | // Do something with the packet 776 | }); 777 | } else { 778 | System.out.println("Listen failed" + asyncResult.cause()); 779 | } 780 | }); 781 | } 782 | 783 | public void example4(Vertx vertx) { 784 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 785 | Buffer buffer = Buffer.buffer("content"); 786 | // Send a Buffer to a multicast address 787 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 788 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 789 | }); 790 | } 791 | 792 | public void example5(Vertx vertx) { 793 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 794 | socket.listen(1234, "0.0.0.0", asyncResult -> { 795 | if (asyncResult.succeeded()) { 796 | socket.handler(packet -> { 797 | // Do something with the packet 798 | }); 799 | 800 | // join the multicast group 801 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 802 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 803 | }); 804 | } else { 805 | System.out.println("Listen failed" + asyncResult.cause()); 806 | } 807 | }); 808 | } 809 | 810 | public void example6(Vertx vertx) { 811 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 812 | socket.listen(1234, "0.0.0.0", asyncResult -> { 813 | if (asyncResult.succeeded()) { 814 | socket.handler(packet -> { 815 | // Do something with the packet 816 | }); 817 | 818 | // join the multicast group 819 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 820 | if (asyncResult2.succeeded()) { 821 | // will now receive packets for group 822 | 823 | // do some work 824 | 825 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 826 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 827 | }); 828 | } else { 829 | System.out.println("Listen failed" + asyncResult2.cause()); 830 | } 831 | }); 832 | } else { 833 | System.out.println("Listen failed" + asyncResult.cause()); 834 | } 835 | }); 836 | } 837 | 838 | public void example7(Vertx vertx) { 839 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 840 | 841 | // Some code 842 | 843 | // This would block packets which are send from 10.0.0.2 844 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 845 | System.out.println("block succeeded? " + asyncResult.succeeded()); 846 | }); 847 | } 848 | } 849 | 850 | ---- 851 | 852 | ===== Blocking multicast 853 | 854 | Beside unlisten a Multicast address it's also possible to just block multicast for a specific sender address. 855 | 856 | Be aware this only work on some Operating Systems and kernel versions. So please check the Operating System 857 | documentation if it's supported. 858 | 859 | This an expert feature. 860 | 861 | To block multicast from a specific address you can call `blockMulticastGroup(...)` on the DatagramSocket 862 | like shown here: 863 | 864 | [source,clojure] 865 | ---- 866 | /* 867 | * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation 868 | * 869 | * This program and the accompanying materials are made available under the 870 | * terms of the Eclipse Public License 2.0 which is available at 871 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 872 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 873 | * 874 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 875 | */ 876 | 877 | package examples; 878 | 879 | import io.vertx.core.Vertx; 880 | import io.vertx.core.buffer.Buffer; 881 | import io.vertx.core.datagram.DatagramSocket; 882 | import io.vertx.core.datagram.DatagramSocketOptions; 883 | 884 | /** 885 | * @author Julien Viet 886 | */ 887 | public class DatagramExamples { 888 | 889 | public void example1(Vertx vertx) { 890 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 891 | } 892 | 893 | public void example2(Vertx vertx) { 894 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 895 | Buffer buffer = Buffer.buffer("content"); 896 | // Send a Buffer 897 | socket.send(buffer, 1234, "10.0.0.1", asyncResult -> { 898 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 899 | }); 900 | // Send a String 901 | socket.send("A string used as content", 1234, "10.0.0.1", asyncResult -> { 902 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 903 | }); 904 | } 905 | 906 | public void example3(Vertx vertx) { 907 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 908 | socket.listen(1234, "0.0.0.0", asyncResult -> { 909 | if (asyncResult.succeeded()) { 910 | socket.handler(packet -> { 911 | // Do something with the packet 912 | }); 913 | } else { 914 | System.out.println("Listen failed" + asyncResult.cause()); 915 | } 916 | }); 917 | } 918 | 919 | public void example4(Vertx vertx) { 920 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 921 | Buffer buffer = Buffer.buffer("content"); 922 | // Send a Buffer to a multicast address 923 | socket.send(buffer, 1234, "230.0.0.1", asyncResult -> { 924 | System.out.println("Send succeeded? " + asyncResult.succeeded()); 925 | }); 926 | } 927 | 928 | public void example5(Vertx vertx) { 929 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 930 | socket.listen(1234, "0.0.0.0", asyncResult -> { 931 | if (asyncResult.succeeded()) { 932 | socket.handler(packet -> { 933 | // Do something with the packet 934 | }); 935 | 936 | // join the multicast group 937 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 938 | System.out.println("Listen succeeded? " + asyncResult2.succeeded()); 939 | }); 940 | } else { 941 | System.out.println("Listen failed" + asyncResult.cause()); 942 | } 943 | }); 944 | } 945 | 946 | public void example6(Vertx vertx) { 947 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 948 | socket.listen(1234, "0.0.0.0", asyncResult -> { 949 | if (asyncResult.succeeded()) { 950 | socket.handler(packet -> { 951 | // Do something with the packet 952 | }); 953 | 954 | // join the multicast group 955 | socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> { 956 | if (asyncResult2.succeeded()) { 957 | // will now receive packets for group 958 | 959 | // do some work 960 | 961 | socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 -> { 962 | System.out.println("Unlisten succeeded? " + asyncResult3.succeeded()); 963 | }); 964 | } else { 965 | System.out.println("Listen failed" + asyncResult2.cause()); 966 | } 967 | }); 968 | } else { 969 | System.out.println("Listen failed" + asyncResult.cause()); 970 | } 971 | }); 972 | } 973 | 974 | public void example7(Vertx vertx) { 975 | DatagramSocket socket = vertx.createDatagramSocket(new DatagramSocketOptions()); 976 | 977 | // Some code 978 | 979 | // This would block packets which are send from 10.0.0.2 980 | socket.blockMulticastGroup("230.0.0.1", "10.0.0.2", asyncResult -> { 981 | System.out.println("block succeeded? " + asyncResult.succeeded()); 982 | }); 983 | } 984 | } 985 | 986 | ---- 987 | 988 | ==== DatagramSocket properties 989 | 990 | When creating a `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` there are multiple properties you can set to 991 | change it's behaviour with the `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html[DatagramSocketOptions]` object. Those are listed here: 992 | 993 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setSendBufferSize-int-[setSendBufferSize]` Sets the send buffer size in bytes. 994 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setReceiveBufferSize-int-[setReceiveBufferSize]` Sets the TCP receive buffer size 995 | in bytes. 996 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setReuseAddress-boolean-[setReuseAddress]` If true then addresses in TIME_WAIT 997 | state can be reused after they have been closed. 998 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setTrafficClass-int-[setTrafficClass]` 999 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setBroadcast-boolean-[setBroadcast]` Sets or clears the SO_BROADCAST socket 1000 | option. When this option is set, Datagram (UDP) packets may be sent to a local interface's broadcast address. 1001 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setMulticastNetworkInterface-java.lang.String-[setMulticastNetworkInterface]` Sets or clears 1002 | the IP_MULTICAST_LOOP socket option. When this option is set, multicast packets will also be received on the 1003 | local interface. 1004 | - `link:../../apidocs/io/vertx/core/datagram/DatagramSocketOptions.html#setMulticastTimeToLive-int-[setMulticastTimeToLive]` Sets the IP_MULTICAST_TTL socket 1005 | option. TTL stands for "Time to Live," but in this context it specifies the number of IP hops that a packet is 1006 | allowed to go through, specifically for multicast traffic. Each router or gateway that forwards a packet decrements 1007 | the TTL. If the TTL is decremented to 0 by a router, it will not be forwarded. 1008 | 1009 | ==== DatagramSocket Local Address 1010 | 1011 | You can find out the local address of the socket (i.e. the address of this side of the UDP Socket) by calling 1012 | `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html#localAddress--[localAddress]`. This will only return an `InetSocketAddress` if you 1013 | bound the `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html[DatagramSocket]` with `listen(...)` before, otherwise it will return null. 1014 | 1015 | ==== Closing a DatagramSocket 1016 | 1017 | You can close a socket by invoking the `link:../../apidocs/io/vertx/core/datagram/DatagramSocket.html#close-io.vertx.core.Handler-[close]` method. This will close 1018 | the socket and release all resources -------------------------------------------------------------------------------- /vertx-lang-clojure/src/main/asciidoc/clojure/shareddata.adoc: -------------------------------------------------------------------------------- 1 | == Using Shared Data with Vert.x 2 | 3 | Shared data contains functionality that allows you to safely share data between different parts of your application, 4 | or different applications in the same Vert.x instance or across a cluster of Vert.x instances. 5 | 6 | Shared data provides: 7 | 8 | * synchronous shared maps (local) 9 | * asynchronous maps (local or cluster-wide) 10 | * asynchronous locks (local or cluster-wide) 11 | * asynchronous counters (local or cluster-wide) 12 | 13 | IMPORTANT: The behavior of the distributed data structure depends on the cluster manager you use. Backup 14 | (replication) and behavior when a network partition is faced are defined by the cluster manager and its 15 | configuration. Refer to the cluster manager documentation as well as to the underlying framework manual. 16 | 17 | === Local shared maps 18 | 19 | `link:../../apidocs/io/vertx/core/shareddata/LocalMap.html[Local shared maps]` allow you to share data safely between different event 20 | loops (e.g. different verticles) in the same Vert.x instance. 21 | 22 | Local shared maps only allow certain data types to be used as keys and values. Those types must either be immutable, 23 | or certain other types that can be copied like `link:../../apidocs/io/vertx/core/buffer/Buffer.html[Buffer]`. In the latter case the key/value 24 | will be copied before putting it in the map. 25 | 26 | This way we can ensure there is no _shared access to mutable state_ between different threads in your Vert.x application 27 | so you don't have to worry about protecting that state by synchronising access to it. 28 | 29 | Here's an example of using a shared local map: 30 | 31 | [source,clojure] 32 | ---- 33 | /* 34 | * Copyright (c) 2014 Red Hat, Inc. and others 35 | * 36 | * This program and the accompanying materials are made available under the 37 | * terms of the Eclipse Public License 2.0 which is available at 38 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 39 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 40 | * 41 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 42 | */ 43 | 44 | package examples; 45 | 46 | import io.vertx.core.Vertx; 47 | import io.vertx.core.buffer.Buffer; 48 | import io.vertx.core.shareddata.AsyncMap; 49 | import io.vertx.core.shareddata.Counter; 50 | import io.vertx.core.shareddata.LocalMap; 51 | import io.vertx.core.shareddata.Lock; 52 | import io.vertx.core.shareddata.SharedData; 53 | 54 | /** 55 | * Created by tim on 19/01/15. 56 | */ 57 | public class SharedDataExamples { 58 | 59 | public void example1(Vertx vertx) { 60 | 61 | SharedData sd = vertx.sharedData(); 62 | 63 | LocalMap map1 = sd.getLocalMap("mymap1"); 64 | 65 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 66 | 67 | LocalMap map2 = sd.getLocalMap("mymap2"); 68 | 69 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 70 | 71 | // Then... in another part of your application: 72 | 73 | map1 = sd.getLocalMap("mymap1"); 74 | 75 | String val = map1.get("foo"); 76 | 77 | map2 = sd.getLocalMap("mymap2"); 78 | 79 | Buffer buff = map2.get("eek"); 80 | } 81 | 82 | public void example2(Vertx vertx) { 83 | 84 | SharedData sd = vertx.sharedData(); 85 | 86 | sd.getAsyncMap("mymap", res -> { 87 | if (res.succeeded()) { 88 | AsyncMap map = res.result(); 89 | } else { 90 | // Something went wrong! 91 | } 92 | }); 93 | 94 | } 95 | 96 | public void example3(AsyncMap map) { 97 | 98 | map.put("foo", "bar", resPut -> { 99 | if (resPut.succeeded()) { 100 | // Successfully put the value 101 | } else { 102 | // Something went wrong! 103 | } 104 | }); 105 | 106 | } 107 | 108 | public void example4(AsyncMap map) { 109 | 110 | map.get("foo", resGet -> { 111 | if (resGet.succeeded()) { 112 | // Successfully got the value 113 | Object val = resGet.result(); 114 | } else { 115 | // Something went wrong! 116 | } 117 | }); 118 | 119 | } 120 | 121 | public void example5(Vertx vertx, SharedData sd) { 122 | sd.getLock("mylock", res -> { 123 | if (res.succeeded()) { 124 | // Got the lock! 125 | Lock lock = res.result(); 126 | 127 | // 5 seconds later we release the lock so someone else can get it 128 | 129 | vertx.setTimer(5000, tid -> lock.release()); 130 | 131 | } else { 132 | // Something went wrong 133 | } 134 | }); 135 | } 136 | 137 | public void example6(SharedData sd) { 138 | sd.getLockWithTimeout("mylock", 10000, res -> { 139 | if (res.succeeded()) { 140 | // Got the lock! 141 | Lock lock = res.result(); 142 | 143 | } else { 144 | // Failed to get lock 145 | } 146 | }); 147 | } 148 | 149 | public void example7(SharedData sd) { 150 | sd.getCounter("mycounter", res -> { 151 | if (res.succeeded()) { 152 | Counter counter = res.result(); 153 | } else { 154 | // Something went wrong! 155 | } 156 | }); 157 | } 158 | 159 | 160 | 161 | } 162 | 163 | ---- 164 | 165 | === Asynchronous shared maps 166 | 167 | Asynchronous shared maps allow data to be put in the map and retrieved locally when Vert.x is not clustered. 168 | When clustered, data can be put from any node and retrieved from the same node or any other node. 169 | 170 | IMPORTANT: In clustered mode, asynchronous shared maps rely on distributed data structures provided by the cluster manager. 171 | Beware that the latency relative to asynchronous shared map operations can be much higher in clustered than in local mode. 172 | 173 | This makes them really useful for things like storing session state in a farm of servers hosting a Vert.x web 174 | application. 175 | 176 | You get an instance of `link:../../apidocs/io/vertx/core/shareddata/AsyncMap.html[AsyncMap]` with 177 | `link:../../apidocs/io/vertx/core/shareddata/SharedData.html#getAsyncMap-java.lang.String-io.vertx.core.Handler-[getAsyncMap]`. 178 | 179 | Getting the map is asynchronous and the result is returned to you in the handler that you specify. Here's an example: 180 | 181 | [source,clojure] 182 | ---- 183 | /* 184 | * Copyright (c) 2014 Red Hat, Inc. and others 185 | * 186 | * This program and the accompanying materials are made available under the 187 | * terms of the Eclipse Public License 2.0 which is available at 188 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 189 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 190 | * 191 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 192 | */ 193 | 194 | package examples; 195 | 196 | import io.vertx.core.Vertx; 197 | import io.vertx.core.buffer.Buffer; 198 | import io.vertx.core.shareddata.AsyncMap; 199 | import io.vertx.core.shareddata.Counter; 200 | import io.vertx.core.shareddata.LocalMap; 201 | import io.vertx.core.shareddata.Lock; 202 | import io.vertx.core.shareddata.SharedData; 203 | 204 | /** 205 | * Created by tim on 19/01/15. 206 | */ 207 | public class SharedDataExamples { 208 | 209 | public void example1(Vertx vertx) { 210 | 211 | SharedData sd = vertx.sharedData(); 212 | 213 | LocalMap map1 = sd.getLocalMap("mymap1"); 214 | 215 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 216 | 217 | LocalMap map2 = sd.getLocalMap("mymap2"); 218 | 219 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 220 | 221 | // Then... in another part of your application: 222 | 223 | map1 = sd.getLocalMap("mymap1"); 224 | 225 | String val = map1.get("foo"); 226 | 227 | map2 = sd.getLocalMap("mymap2"); 228 | 229 | Buffer buff = map2.get("eek"); 230 | } 231 | 232 | public void example2(Vertx vertx) { 233 | 234 | SharedData sd = vertx.sharedData(); 235 | 236 | sd.getAsyncMap("mymap", res -> { 237 | if (res.succeeded()) { 238 | AsyncMap map = res.result(); 239 | } else { 240 | // Something went wrong! 241 | } 242 | }); 243 | 244 | } 245 | 246 | public void example3(AsyncMap map) { 247 | 248 | map.put("foo", "bar", resPut -> { 249 | if (resPut.succeeded()) { 250 | // Successfully put the value 251 | } else { 252 | // Something went wrong! 253 | } 254 | }); 255 | 256 | } 257 | 258 | public void example4(AsyncMap map) { 259 | 260 | map.get("foo", resGet -> { 261 | if (resGet.succeeded()) { 262 | // Successfully got the value 263 | Object val = resGet.result(); 264 | } else { 265 | // Something went wrong! 266 | } 267 | }); 268 | 269 | } 270 | 271 | public void example5(Vertx vertx, SharedData sd) { 272 | sd.getLock("mylock", res -> { 273 | if (res.succeeded()) { 274 | // Got the lock! 275 | Lock lock = res.result(); 276 | 277 | // 5 seconds later we release the lock so someone else can get it 278 | 279 | vertx.setTimer(5000, tid -> lock.release()); 280 | 281 | } else { 282 | // Something went wrong 283 | } 284 | }); 285 | } 286 | 287 | public void example6(SharedData sd) { 288 | sd.getLockWithTimeout("mylock", 10000, res -> { 289 | if (res.succeeded()) { 290 | // Got the lock! 291 | Lock lock = res.result(); 292 | 293 | } else { 294 | // Failed to get lock 295 | } 296 | }); 297 | } 298 | 299 | public void example7(SharedData sd) { 300 | sd.getCounter("mycounter", res -> { 301 | if (res.succeeded()) { 302 | Counter counter = res.result(); 303 | } else { 304 | // Something went wrong! 305 | } 306 | }); 307 | } 308 | 309 | 310 | 311 | } 312 | 313 | ---- 314 | 315 | ==== Putting data in a map 316 | 317 | You put data in a map with `link:../../apidocs/io/vertx/core/shareddata/AsyncMap.html#put-java.lang.Object-java.lang.Object-io.vertx.core.Handler-[put]`. 318 | 319 | The actual put is asynchronous and the handler is notified once it is complete: 320 | 321 | [source,clojure] 322 | ---- 323 | /* 324 | * Copyright (c) 2014 Red Hat, Inc. and others 325 | * 326 | * This program and the accompanying materials are made available under the 327 | * terms of the Eclipse Public License 2.0 which is available at 328 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 329 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 330 | * 331 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 332 | */ 333 | 334 | package examples; 335 | 336 | import io.vertx.core.Vertx; 337 | import io.vertx.core.buffer.Buffer; 338 | import io.vertx.core.shareddata.AsyncMap; 339 | import io.vertx.core.shareddata.Counter; 340 | import io.vertx.core.shareddata.LocalMap; 341 | import io.vertx.core.shareddata.Lock; 342 | import io.vertx.core.shareddata.SharedData; 343 | 344 | /** 345 | * Created by tim on 19/01/15. 346 | */ 347 | public class SharedDataExamples { 348 | 349 | public void example1(Vertx vertx) { 350 | 351 | SharedData sd = vertx.sharedData(); 352 | 353 | LocalMap map1 = sd.getLocalMap("mymap1"); 354 | 355 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 356 | 357 | LocalMap map2 = sd.getLocalMap("mymap2"); 358 | 359 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 360 | 361 | // Then... in another part of your application: 362 | 363 | map1 = sd.getLocalMap("mymap1"); 364 | 365 | String val = map1.get("foo"); 366 | 367 | map2 = sd.getLocalMap("mymap2"); 368 | 369 | Buffer buff = map2.get("eek"); 370 | } 371 | 372 | public void example2(Vertx vertx) { 373 | 374 | SharedData sd = vertx.sharedData(); 375 | 376 | sd.getAsyncMap("mymap", res -> { 377 | if (res.succeeded()) { 378 | AsyncMap map = res.result(); 379 | } else { 380 | // Something went wrong! 381 | } 382 | }); 383 | 384 | } 385 | 386 | public void example3(AsyncMap map) { 387 | 388 | map.put("foo", "bar", resPut -> { 389 | if (resPut.succeeded()) { 390 | // Successfully put the value 391 | } else { 392 | // Something went wrong! 393 | } 394 | }); 395 | 396 | } 397 | 398 | public void example4(AsyncMap map) { 399 | 400 | map.get("foo", resGet -> { 401 | if (resGet.succeeded()) { 402 | // Successfully got the value 403 | Object val = resGet.result(); 404 | } else { 405 | // Something went wrong! 406 | } 407 | }); 408 | 409 | } 410 | 411 | public void example5(Vertx vertx, SharedData sd) { 412 | sd.getLock("mylock", res -> { 413 | if (res.succeeded()) { 414 | // Got the lock! 415 | Lock lock = res.result(); 416 | 417 | // 5 seconds later we release the lock so someone else can get it 418 | 419 | vertx.setTimer(5000, tid -> lock.release()); 420 | 421 | } else { 422 | // Something went wrong 423 | } 424 | }); 425 | } 426 | 427 | public void example6(SharedData sd) { 428 | sd.getLockWithTimeout("mylock", 10000, res -> { 429 | if (res.succeeded()) { 430 | // Got the lock! 431 | Lock lock = res.result(); 432 | 433 | } else { 434 | // Failed to get lock 435 | } 436 | }); 437 | } 438 | 439 | public void example7(SharedData sd) { 440 | sd.getCounter("mycounter", res -> { 441 | if (res.succeeded()) { 442 | Counter counter = res.result(); 443 | } else { 444 | // Something went wrong! 445 | } 446 | }); 447 | } 448 | 449 | 450 | 451 | } 452 | 453 | ---- 454 | 455 | ==== Getting data from a map 456 | 457 | You get data from a map with `link:../../apidocs/io/vertx/core/shareddata/AsyncMap.html#get-java.lang.Object-io.vertx.core.Handler-[get]`. 458 | 459 | The actual get is asynchronous and the handler is notified with the result some time later 460 | 461 | [source,clojure] 462 | ---- 463 | /* 464 | * Copyright (c) 2014 Red Hat, Inc. and others 465 | * 466 | * This program and the accompanying materials are made available under the 467 | * terms of the Eclipse Public License 2.0 which is available at 468 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 469 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 470 | * 471 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 472 | */ 473 | 474 | package examples; 475 | 476 | import io.vertx.core.Vertx; 477 | import io.vertx.core.buffer.Buffer; 478 | import io.vertx.core.shareddata.AsyncMap; 479 | import io.vertx.core.shareddata.Counter; 480 | import io.vertx.core.shareddata.LocalMap; 481 | import io.vertx.core.shareddata.Lock; 482 | import io.vertx.core.shareddata.SharedData; 483 | 484 | /** 485 | * Created by tim on 19/01/15. 486 | */ 487 | public class SharedDataExamples { 488 | 489 | public void example1(Vertx vertx) { 490 | 491 | SharedData sd = vertx.sharedData(); 492 | 493 | LocalMap map1 = sd.getLocalMap("mymap1"); 494 | 495 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 496 | 497 | LocalMap map2 = sd.getLocalMap("mymap2"); 498 | 499 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 500 | 501 | // Then... in another part of your application: 502 | 503 | map1 = sd.getLocalMap("mymap1"); 504 | 505 | String val = map1.get("foo"); 506 | 507 | map2 = sd.getLocalMap("mymap2"); 508 | 509 | Buffer buff = map2.get("eek"); 510 | } 511 | 512 | public void example2(Vertx vertx) { 513 | 514 | SharedData sd = vertx.sharedData(); 515 | 516 | sd.getAsyncMap("mymap", res -> { 517 | if (res.succeeded()) { 518 | AsyncMap map = res.result(); 519 | } else { 520 | // Something went wrong! 521 | } 522 | }); 523 | 524 | } 525 | 526 | public void example3(AsyncMap map) { 527 | 528 | map.put("foo", "bar", resPut -> { 529 | if (resPut.succeeded()) { 530 | // Successfully put the value 531 | } else { 532 | // Something went wrong! 533 | } 534 | }); 535 | 536 | } 537 | 538 | public void example4(AsyncMap map) { 539 | 540 | map.get("foo", resGet -> { 541 | if (resGet.succeeded()) { 542 | // Successfully got the value 543 | Object val = resGet.result(); 544 | } else { 545 | // Something went wrong! 546 | } 547 | }); 548 | 549 | } 550 | 551 | public void example5(Vertx vertx, SharedData sd) { 552 | sd.getLock("mylock", res -> { 553 | if (res.succeeded()) { 554 | // Got the lock! 555 | Lock lock = res.result(); 556 | 557 | // 5 seconds later we release the lock so someone else can get it 558 | 559 | vertx.setTimer(5000, tid -> lock.release()); 560 | 561 | } else { 562 | // Something went wrong 563 | } 564 | }); 565 | } 566 | 567 | public void example6(SharedData sd) { 568 | sd.getLockWithTimeout("mylock", 10000, res -> { 569 | if (res.succeeded()) { 570 | // Got the lock! 571 | Lock lock = res.result(); 572 | 573 | } else { 574 | // Failed to get lock 575 | } 576 | }); 577 | } 578 | 579 | public void example7(SharedData sd) { 580 | sd.getCounter("mycounter", res -> { 581 | if (res.succeeded()) { 582 | Counter counter = res.result(); 583 | } else { 584 | // Something went wrong! 585 | } 586 | }); 587 | } 588 | 589 | 590 | 591 | } 592 | 593 | ---- 594 | 595 | ===== Other map operations 596 | 597 | You can also remove entries from an asynchronous map, clear them and get the size. 598 | 599 | See the `link:../../apidocs/io/vertx/core/shareddata/AsyncMap.html[API docs]` for more information. 600 | 601 | === Asynchronous locks 602 | 603 | `link:../../apidocs/io/vertx/core/shareddata/Lock.html[Asynchronous locks]` allow you to obtain exclusive locks locally or across the cluster - 604 | this is useful when you want to do something or access a resource on only one node of a cluster at any one time. 605 | 606 | Asynchronous locks have an asynchronous API unlike most lock APIs which block the calling thread until the lock 607 | is obtained. 608 | 609 | To obtain a lock use `link:../../apidocs/io/vertx/core/shareddata/SharedData.html#getLock-java.lang.String-io.vertx.core.Handler-[getLock]`. 610 | 611 | This won't block, but when the lock is available, the handler will be called with an instance of `link:../../apidocs/io/vertx/core/shareddata/Lock.html[Lock]`, 612 | signifying that you now own the lock. 613 | 614 | While you own the lock no other caller, anywhere on the cluster will be able to obtain the lock. 615 | 616 | When you've finished with the lock, you call `link:../../apidocs/io/vertx/core/shareddata/Lock.html#release--[release]` to release it, so 617 | another caller can obtain it. 618 | 619 | [source,clojure] 620 | ---- 621 | /* 622 | * Copyright (c) 2014 Red Hat, Inc. and others 623 | * 624 | * This program and the accompanying materials are made available under the 625 | * terms of the Eclipse Public License 2.0 which is available at 626 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 627 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 628 | * 629 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 630 | */ 631 | 632 | package examples; 633 | 634 | import io.vertx.core.Vertx; 635 | import io.vertx.core.buffer.Buffer; 636 | import io.vertx.core.shareddata.AsyncMap; 637 | import io.vertx.core.shareddata.Counter; 638 | import io.vertx.core.shareddata.LocalMap; 639 | import io.vertx.core.shareddata.Lock; 640 | import io.vertx.core.shareddata.SharedData; 641 | 642 | /** 643 | * Created by tim on 19/01/15. 644 | */ 645 | public class SharedDataExamples { 646 | 647 | public void example1(Vertx vertx) { 648 | 649 | SharedData sd = vertx.sharedData(); 650 | 651 | LocalMap map1 = sd.getLocalMap("mymap1"); 652 | 653 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 654 | 655 | LocalMap map2 = sd.getLocalMap("mymap2"); 656 | 657 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 658 | 659 | // Then... in another part of your application: 660 | 661 | map1 = sd.getLocalMap("mymap1"); 662 | 663 | String val = map1.get("foo"); 664 | 665 | map2 = sd.getLocalMap("mymap2"); 666 | 667 | Buffer buff = map2.get("eek"); 668 | } 669 | 670 | public void example2(Vertx vertx) { 671 | 672 | SharedData sd = vertx.sharedData(); 673 | 674 | sd.getAsyncMap("mymap", res -> { 675 | if (res.succeeded()) { 676 | AsyncMap map = res.result(); 677 | } else { 678 | // Something went wrong! 679 | } 680 | }); 681 | 682 | } 683 | 684 | public void example3(AsyncMap map) { 685 | 686 | map.put("foo", "bar", resPut -> { 687 | if (resPut.succeeded()) { 688 | // Successfully put the value 689 | } else { 690 | // Something went wrong! 691 | } 692 | }); 693 | 694 | } 695 | 696 | public void example4(AsyncMap map) { 697 | 698 | map.get("foo", resGet -> { 699 | if (resGet.succeeded()) { 700 | // Successfully got the value 701 | Object val = resGet.result(); 702 | } else { 703 | // Something went wrong! 704 | } 705 | }); 706 | 707 | } 708 | 709 | public void example5(Vertx vertx, SharedData sd) { 710 | sd.getLock("mylock", res -> { 711 | if (res.succeeded()) { 712 | // Got the lock! 713 | Lock lock = res.result(); 714 | 715 | // 5 seconds later we release the lock so someone else can get it 716 | 717 | vertx.setTimer(5000, tid -> lock.release()); 718 | 719 | } else { 720 | // Something went wrong 721 | } 722 | }); 723 | } 724 | 725 | public void example6(SharedData sd) { 726 | sd.getLockWithTimeout("mylock", 10000, res -> { 727 | if (res.succeeded()) { 728 | // Got the lock! 729 | Lock lock = res.result(); 730 | 731 | } else { 732 | // Failed to get lock 733 | } 734 | }); 735 | } 736 | 737 | public void example7(SharedData sd) { 738 | sd.getCounter("mycounter", res -> { 739 | if (res.succeeded()) { 740 | Counter counter = res.result(); 741 | } else { 742 | // Something went wrong! 743 | } 744 | }); 745 | } 746 | 747 | 748 | 749 | } 750 | 751 | ---- 752 | 753 | You can also get a lock with a timeout. If it fails to obtain the lock within the timeout the handler will be called 754 | with a failure: 755 | 756 | [source,clojure] 757 | ---- 758 | /* 759 | * Copyright (c) 2014 Red Hat, Inc. and others 760 | * 761 | * This program and the accompanying materials are made available under the 762 | * terms of the Eclipse Public License 2.0 which is available at 763 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 764 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 765 | * 766 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 767 | */ 768 | 769 | package examples; 770 | 771 | import io.vertx.core.Vertx; 772 | import io.vertx.core.buffer.Buffer; 773 | import io.vertx.core.shareddata.AsyncMap; 774 | import io.vertx.core.shareddata.Counter; 775 | import io.vertx.core.shareddata.LocalMap; 776 | import io.vertx.core.shareddata.Lock; 777 | import io.vertx.core.shareddata.SharedData; 778 | 779 | /** 780 | * Created by tim on 19/01/15. 781 | */ 782 | public class SharedDataExamples { 783 | 784 | public void example1(Vertx vertx) { 785 | 786 | SharedData sd = vertx.sharedData(); 787 | 788 | LocalMap map1 = sd.getLocalMap("mymap1"); 789 | 790 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 791 | 792 | LocalMap map2 = sd.getLocalMap("mymap2"); 793 | 794 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 795 | 796 | // Then... in another part of your application: 797 | 798 | map1 = sd.getLocalMap("mymap1"); 799 | 800 | String val = map1.get("foo"); 801 | 802 | map2 = sd.getLocalMap("mymap2"); 803 | 804 | Buffer buff = map2.get("eek"); 805 | } 806 | 807 | public void example2(Vertx vertx) { 808 | 809 | SharedData sd = vertx.sharedData(); 810 | 811 | sd.getAsyncMap("mymap", res -> { 812 | if (res.succeeded()) { 813 | AsyncMap map = res.result(); 814 | } else { 815 | // Something went wrong! 816 | } 817 | }); 818 | 819 | } 820 | 821 | public void example3(AsyncMap map) { 822 | 823 | map.put("foo", "bar", resPut -> { 824 | if (resPut.succeeded()) { 825 | // Successfully put the value 826 | } else { 827 | // Something went wrong! 828 | } 829 | }); 830 | 831 | } 832 | 833 | public void example4(AsyncMap map) { 834 | 835 | map.get("foo", resGet -> { 836 | if (resGet.succeeded()) { 837 | // Successfully got the value 838 | Object val = resGet.result(); 839 | } else { 840 | // Something went wrong! 841 | } 842 | }); 843 | 844 | } 845 | 846 | public void example5(Vertx vertx, SharedData sd) { 847 | sd.getLock("mylock", res -> { 848 | if (res.succeeded()) { 849 | // Got the lock! 850 | Lock lock = res.result(); 851 | 852 | // 5 seconds later we release the lock so someone else can get it 853 | 854 | vertx.setTimer(5000, tid -> lock.release()); 855 | 856 | } else { 857 | // Something went wrong 858 | } 859 | }); 860 | } 861 | 862 | public void example6(SharedData sd) { 863 | sd.getLockWithTimeout("mylock", 10000, res -> { 864 | if (res.succeeded()) { 865 | // Got the lock! 866 | Lock lock = res.result(); 867 | 868 | } else { 869 | // Failed to get lock 870 | } 871 | }); 872 | } 873 | 874 | public void example7(SharedData sd) { 875 | sd.getCounter("mycounter", res -> { 876 | if (res.succeeded()) { 877 | Counter counter = res.result(); 878 | } else { 879 | // Something went wrong! 880 | } 881 | }); 882 | } 883 | 884 | 885 | 886 | } 887 | 888 | ---- 889 | 890 | === Asynchronous counters 891 | 892 | It's often useful to maintain an atomic counter locally or across the different nodes of your application. 893 | 894 | You can do this with `link:../../apidocs/io/vertx/core/shareddata/Counter.html[Counter]`. 895 | 896 | You obtain an instance with `link:../../apidocs/io/vertx/core/shareddata/SharedData.html#getCounter-java.lang.String-io.vertx.core.Handler-[getCounter]`: 897 | 898 | [source,clojure] 899 | ---- 900 | /* 901 | * Copyright (c) 2014 Red Hat, Inc. and others 902 | * 903 | * This program and the accompanying materials are made available under the 904 | * terms of the Eclipse Public License 2.0 which is available at 905 | * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 906 | * which is available at https://www.apache.org/licenses/LICENSE-2.0. 907 | * 908 | * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 909 | */ 910 | 911 | package examples; 912 | 913 | import io.vertx.core.Vertx; 914 | import io.vertx.core.buffer.Buffer; 915 | import io.vertx.core.shareddata.AsyncMap; 916 | import io.vertx.core.shareddata.Counter; 917 | import io.vertx.core.shareddata.LocalMap; 918 | import io.vertx.core.shareddata.Lock; 919 | import io.vertx.core.shareddata.SharedData; 920 | 921 | /** 922 | * Created by tim on 19/01/15. 923 | */ 924 | public class SharedDataExamples { 925 | 926 | public void example1(Vertx vertx) { 927 | 928 | SharedData sd = vertx.sharedData(); 929 | 930 | LocalMap map1 = sd.getLocalMap("mymap1"); 931 | 932 | map1.put("foo", "bar"); // Strings are immutable so no need to copy 933 | 934 | LocalMap map2 = sd.getLocalMap("mymap2"); 935 | 936 | map2.put("eek", Buffer.buffer().appendInt(123)); // This buffer will be copied before adding to map 937 | 938 | // Then... in another part of your application: 939 | 940 | map1 = sd.getLocalMap("mymap1"); 941 | 942 | String val = map1.get("foo"); 943 | 944 | map2 = sd.getLocalMap("mymap2"); 945 | 946 | Buffer buff = map2.get("eek"); 947 | } 948 | 949 | public void example2(Vertx vertx) { 950 | 951 | SharedData sd = vertx.sharedData(); 952 | 953 | sd.getAsyncMap("mymap", res -> { 954 | if (res.succeeded()) { 955 | AsyncMap map = res.result(); 956 | } else { 957 | // Something went wrong! 958 | } 959 | }); 960 | 961 | } 962 | 963 | public void example3(AsyncMap map) { 964 | 965 | map.put("foo", "bar", resPut -> { 966 | if (resPut.succeeded()) { 967 | // Successfully put the value 968 | } else { 969 | // Something went wrong! 970 | } 971 | }); 972 | 973 | } 974 | 975 | public void example4(AsyncMap 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 | --------------------------------------------------------------------------------