본문 바로가기

[IT/Programming]/HTML related

Learning Vert.x

반응형
# Learning Vert.x Vert.x 를 배워봅시다. (version 3.0.0 이 나오면서 뭔가 많이 바뀐듯?) 가장 비슷한 server-side 언어가 node.js 일듯? Vert.x 자체가 node.js 로부터 영향을 받은 프로젝트이기 때문에 node.js 의 많은 장점들을 가져와서 구현했을듯. JVM (Java Vertual Machine) 에서 돌아가기 때문에 "Java, JavaScript, Python, Groovy, Scala" 등 node.js 보다 다양한 언어가 지원된다고. 이런걸 polyglot (여러 언어를 말하는) 특성이라고 하는듯. 그래도 기본적으로 Java 로 돌아가는 놈이라 다른언어로 작성했을때도 vertx 의 모든 기능 및 장점을 사용할 수 있을지는 잘 모르겠음. 그런데 에서의 vert.x 성적이 몇년전엔 그렇게 좋지 않았는데... 최근 round 에서는 꽤나 높은 순위를 달리는 중인듯. 11위 vert.x, 19위 vert.x-web. ## PH
  • 2023-05-26 : 성능 test Round update.
  • 2015-12-13 : Embeded vert.x 관련 ref 링크 추가.
  • 2014-05-23 : First posting.
## TOC ## Hello World! 기본적으로 window 에서는 batch file (vertx.bat) 로 실행됨. 확장자가 없는 vertx file 은 linux 에서 쓰는듯하고. Window 에서 기본적으로 %PATH%"...\java\bin" 위치와 "...\vertx\bin" 위치를 넣어주고, %JAVA_HOME%=...\java%VERTX_HOME% 도 설정해주면 좋고, %CLASSPATH%는 " (quotation mark) 없이 classpath 폴더 목록들 넣어주고. (set CLASSPATH=%CLASSPATH%;%VERTX_HOME%\conf;%VERTX_HOME%\lib\* 와 같은 명령어가 batch file에 들어있어서 따로 vertx class들의 path는 안넣어놔도 되는듯.) 설치가 잘 되었는지 확인하기 위해 cmd 창에 vertx -version 입력하면 3.0.0와 같이 버전이 표시되어야 함. 가장 기본적인 "Hello World" 테스트는 아래와 같은 "HelloWorldServer.java" 파일을 만든 뒤, ```[.linenums.lang-java] import org.vertx.java.core.Handler; import org.vertx.java.core.http.HttpServerRequest; import org.vertx.java.platform.Verticle; public class HelloWorldServer extends Verticle { @Override public void start() { // Using lambda expression of JAVA, // ``` // vertx.createHttpServer().requestHandler(new Handler<HttpServerRequest>() { // public void handle(HttpServerRequest req) { req: doing something } // } // ``` // can become simple like this. vertx.createHttpServer().requestHandler( (req) -> { req.response().headers().set("Content-Type","text/html"); req.response().end("<h1>Hello World</h1>"); }).listen(1001); } } ```/ cmd 창에서 vertx run HelloWorldServer.java 실행 후. Browser 로 localhost:1001에 접속하면 "Hello World"가 뜸. 실행되면 Succeeded in deploying verticle 에 멈춰있는데, 하나 실행하면 다른건 못하는건가? =ㅇ=;;; 취소는 Ctrl+C (Cancel 인듯?) 누르면, Terminate batch job (Y/N)? 가 뜨면서 취소할 수 있는듯. (단 'N'을 쳐도 취소된다는거. Ctrl+Break 로는 멈추진 않고 뭔가 장황하게 뜨기만 함.) 실제 batch 파일에서 마지막 실행은 ```[.linenums] "%JAVA_EXE%" %JVM_OPTS% %JMX_OPTS% %JAVA_OPTS% %VERTX_OPTS% %VERTX_MODULE_OPTS% -Djava.util.logging.config.file="%VERTX_JUL_CONFIG%" -Dvertx.home="%VERTX_HOME%" -Dvertx.clusterManagerFactory="%VERTX_CLUSTERMANAGERFACTORY%" -classpath "%CLASSPATH%" org.vertx.java.platform.impl.cli.Starter %CMD_LINE_ARGS% // empty variables. java.exe -Djava.util.logging.config.file="...\vert.x-2.1\conf\logging.properties" -Dvertx.home="...\vert.x-2.1" -Dvertx.clusterManagerFactory="org.vertx.java.spi.cluster.impl.hazelcast.HazelcastClusterManagerFactory" -classpath ".;...\jdk1.8.0_05\lib\;...\classes;...vert.x-2.1conf;...vert.x-2.1lib*" org.vertx.java.platform.impl.cli.Starter run HelloWorldServer.java // 실제로 실행시키는 것은 "org.vertx.java.platform.impl.cli.Starter" class의 main 함수인듯. Args로 "run HelloWorldServer.java"를 전달하는 것이고. javac.exe가 아니기 때문에 compile하는게 아니고 Starter class 내부에서 "HelloWorldServer.java"를 컴파일을 해주고 실행까지 해주는 것인듯. ```/ 와 같이 일어나는듯. Vert.x bin 폴더에 있는 batch 파일 열어보면 나옴. ### vertx.bat file
JVM_OPTS=-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 is deleted. JAVA 가 update 되면서 해당 option 이 에러가 남.
```[.linenums.scrollable.lang-bat] @if "%DEBUG%" == "" @echo off setlocal EnableDelayedExpansion @rem ########################################################################## @rem @rem vertx startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and VERTX_OPTS to pass JVM options to this script. @rem You can configure any property on VertxOptions or DeploymentOptions by setting system properties e.g. @rem set VERTX_OPTS=-Dvertx.options.eventLoopPoolSize=26 -Dvertx.options.deployment.worker=true @rem To enable vert.x sync agent, set the "ENABLE_VERTX_SYNC_AGENT" environment variable to "true". Be aware that you @rem need to install vert.x sync in the $VERTX_HOME/lib directory before. @rem set JVM_OPTS=-Dfile.encoding=UTF8 -XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 set JVM_OPTS=-Dfile.encoding=UTF8 set JMX_OPTS= @rem To enable JMX uncomment the following @rem set JMX_OPTS=-Dcom.sun.management.jmxremote -Dhazelcast.jmx=true -Dvertx.metrics.options.jmxEnabled=true set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set VERTX_HOME=%DIRNAME%.. @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Add module option to commandline, if VERTX_MODS was set if not "%VERTX_MODS%" == "" set VERTX_MODULE_OPTS="-Dvertx.mods=%VERTX_MODS%" @rem enable vert.x sync agent if "%ENABLE_VERTX_SYNC_AGENT%" == "true" ( echo Enabling vert.x sync agent - please make sure vert.x sync and its dependencies have been installed in the 'lib' directory. for %%a in (%VERTX_HOME%\lib\quasar-core-*.jar) do set VERTX_SYNC_AGENT="-javaagent:%%a" ) @rem Configure JUL using custom properties file if "%VERTX_JUL_CONFIG%" == "" set VERTX_JUL_CONFIG=%VERTX_HOME%\conf\logging.properties @rem Specify ClusterManagerFactory if "%VERTX_CLUSTERMANAGERFACTORY%" == "" set VERTX_CLUSTERMANAGERFACTORY=io.vertx.spi.cluster.impl.hazelcast.HazelcastClusterManagerFactory @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line @rem set CLASSPATH=%CLASSPATH%;%VERTX_HOME%\conf;%VERTX_HOME%\lib\* @rem Execute vertx "%JAVA_EXE%" %JVM_OPTS% %JMX_OPTS% %JAVA_OPTS% %VERTX_SYNC_AGENT% %VERTX_OPTS% %VERTX_MODULE_OPTS% -Dvertx.cli.usage.prefix=vertx -Djava.util.logging.config.file="%VERTX_JUL_CONFIG%" -Dvertx.home="%VERTX_HOME%" -Dvertx.clusterManagerFactory="%VERTX_CLUSTERMANAGERFACTORY%" -classpath "%CLASSPATH%" io.vertx.core.Launcher %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable VERTX_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%VERTX_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ```/ ### Encoding UTF-8 한글 출력 관련해서는 vertx.bat 파일에서 ```set JVM_OPTS=-Dfile.encoding=UTF8```/ 와 같이 써줘야 하는듯도... (정확한 reference를 찾아야 할텐데;;;;;; 어거지로 해결한듯한.) 보통 JAVA에서 인코딩은 컴파일 단계에서 ```javac -encoding utf8 -sourcepath "%sp%" %~nx1 -d "%cp%" -classpath "%CLASSPATH%"```/ 와 같이 설정해주는 것으로 알고 있었는데, 위에건 아예 실행시 설정을 바꾸는 것인듯? ```java -Dfile.encoding=UTF8 -classpath "%CLASSPATH%" file.class args```/ 처럼 batch 파일에서 실행시켜 줌. ### TCP echo server 또다른 간단한 테스트 예제로 TCP telnet echo server 가 있음. 파일 "TCPechoServer.java"를 만들어 다음과 같이 저장한 뒤, ```[.linenums.lang-java] import org.vertx.java.core.Handler; import org.vertx.java.core.net.NetSocket; import org.vertx.java.core.streams.Pump; import org.vertx.java.platform.Verticle; // Every Java verticle must extend the class org.vertx.java.deploy.Verticle. You must override the start method - this is called by Vert.x when the verticle is started. public class TCPechoServer extends Verticle{ public void start(){ // vertx.createNetServer().connectHandler(new Handler<NetSocket>(){ // public void handle(final NetSocket socket){ // Pump.createPump(socket, socket).start(); // } // }).listen(1234); vertx.createNetServer().connectHandler( (socket) -> { Pump.createPump(socket, socket).start(); }).listen(1234); } } ```/ cmd 창에 telnet localhost 1234 를 입력하면, TThhiiss iiss eecchhoo sseerrvveerr.. 와 같이 타자치는걸 그대로 베껴서 쏴주는 서버가 만들어짐. (그런데 어떻게 나가지?) ### Verticle \subset Module Verticle은 particle 비슷한 개념의 "execution unit of Vert.x" 이고, module 이란 것으로 이런 verticle 들을 감쌀 수 있음. (Grouping/Wrapping) Raw verticle 은 vertx run foo.js -conf myconf.json 와 같이 실행하고 (요건 JAVA 로 작성한 코드가 아니라 javascript 로 작성한 서버코드), module 은 vertx runmod com.mycompany~my-mod~1.0 -conf myconf.json 와 같이 실행. -conf 로 configuration 을 JSON 파일로 줄 수 있음. 이렇게 설정한 configuration 은 verticle 내에서도 다음과 같은 형태로 접근 가능. ```[.linenums.lang-java] import org.vertx.java.core.json.JsonObject; JsonObject config = container.config(); System.out.println("Config is " + config); ```/ ### Log 여러 간단한 기록을 남기고 싶을 때 쓰는. 아니면 잘 돌아가는지 테스트 할때도 쓰이고. ## Classes
org.vertx.java.platform.Verticle: A verticle is the unit of execution in the Vert.x platform.
## HTTP Server HTTP Server 에서 데이터를 받을때 방법이 꽤나 여러가지인듯? 데이터 크기가 클 경우 중간중간 데이터들을 잘라서 처리할 수 있도록 해주려고 그런거 같은데... 대충 아래와 같은 세가지 function 이 제공됨. Ref. - Writing HTTP Servers and Clients - Writing HTTP servers - Handling HTTP Requests - Reading Data from the Request Body : req.dataHandler, req.endHandler, req.bodyHandler 요렇게 세개? 데이터를 보내는 쪽에서 chunked option 을 켜놔야 (req.response().setChunked(true); 와 같은 명령어로) 받는 쪽에서도 chunked data 를 처리할 수 있음. 그러니 chunked option 같은게 안켜져 있다면 그냥 req.bodyHandler 써야함. 전체 데이터를 받은 다음 처리하는 놈. 아래는 그냥 JAVA lambda expression 이용한 예제. ```[.linenums.scrollable.lang-java] ///////////////////////////////////////////// // Reading Data from the Request Body (Request Header is firstly handled, and Body is handled later.) ///////////////////////////////////////////// final Buffer body = new Buffer(0); req.dataHandler( (Buffer data) -> { System.out.println("\nI received "+data.length()+" bytes."); // System.out.println("data: "+data); body.appendBuffer(data); }); // receive each HTTP chunk of the request body. req.endHandler( (event) -> { System.out.println("\nHttpServerRequest including the total body is ended with body.length(): "+body.length()+" ."); // System.out.println("event: "+event); // null System.out.println("data orginal: "+body); try { System.out.println(URLDecoder.decode( ("data: 한글\n"+body).replaceAll("&","\n").replaceAll("=","\t=\t") , encoding)); } catch (Exception e) { System.out.println(e); } req.response().headers().set("Content-Type","text/html; charset=utf-8"); req.response().end( ("<script>document.write( decodeURIComponent('" +"data: 한글<br>"+body +"') );</script>") .replaceAll("&","<br>").replaceAll("=","\t=\t") , encoding); }); // req.bodyHandler( (Buffer data) -> { // System.out.println("I received the total body of "+data.length()+" bytes."); // }); // bodyHandler override dataHandler and endHandler??? ```/ ### Hard Example (Recoeve.net server) 참조: GitHub--Recoeve.net codes , kipid's Recoeve.net example . ```[.linenums.scrollable.lang-java] import io.vertx.core.AbstractVerticle; // import io.vertx.core.Verticle; // import org.vertx.java.core.Handler; // import org.vertx.java.core.http.HttpServer; // Interface import io.vertx.core.buffer.Buffer; // import io.vertx.core.http.ClientAuth; import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.net.JksOptions; import io.vertx.core.net.TCPSSLOptions; import io.vertx.ext.web.Router; import java.sql.*; import java.util.HashMap; import java.util.List; import java.util.Map; import java.net.URLDecoder; // deprecated API? // import java.io.File; // import java.io.FileReader; // import java.io.IOException; import java.io.UnsupportedEncodingException; // import java.lang.StringBuffer; import java.lang.StringBuilder; import recoeve.http.Cookie; import recoeve.http.BodyData; import recoeve.db.RecoeveDB; import recoeve.db.FileMap; import recoeve.db.FileMapWithVar; import recoeve.db.StrArray; public class Recoeve extends AbstractVerticle { public static final String host ="recoeve.net"; // ="0.0.0.0"; // ="localhost"; public static final String ENCODING="UTF-8"; public static final String INVALID_ACCESS="INVALID ACCESS"; private static long numberOfClients; static { numberOfClients=0; } @Override public void start() { RecoeveDB db=new RecoeveDB(); Router router=Router.router(vertx); router.route().handler(ctx -> { HttpServerRequest req=ctx.request(); //////////////////////////////////// // Console log. //////////////////////////////////// System.out.println("\n\nA client has connected!: "+(++numberOfClients)); final String now=db.now(); final String referer=req.headers().get("Referer"); System.out.println("Time: "+now); if (referer!=null) { try { System.out.println("Referer: "+URLDecoder.decode(referer, "UTF-8")); } catch (UnsupportedEncodingException e) { System.out.println(e); } } else { System.out.println("Referer: null"); } boolean refererAllowed=false; if (referer==null) { refererAllowed=true; } else if (referer.substring(0,4).toLowerCase().equals("http")) { int k=4; if (referer.charAt(k)=='s'||referer.charAt(k)=='S') { k++; } if (referer.startsWith("://",k)) { k+=3; int l=referer.indexOf('/',k); String refererHost=null; if (l==-1) { refererHost=referer.substring(k); } else { refererHost=referer.substring(k,l); } refererAllowed=FileMap.refererAllowed(refererHost); System.out.println("Referer Host: "+refererHost); } } System.out.println("Referer Allowed: "+refererAllowed); final HttpMethod method=req.method(); final String path=req.path(); final String query=req.query(); System.out.println("Method: "+method); try { System.out.println("Absolute URI: "+URLDecoder.decode(req.absoluteURI(), "UTF-8")); } catch (UnsupportedEncodingException e) { System.out.println(e); } final String ip=req.remoteAddress().toString(); System.out.println("User IP: "+ip); System.out.println("Local Address: "+req.localAddress()); //////////////////////////////////// // Session cookie 확인. //////////////////////////////////// final Cookie cookie=new Cookie(req.headers().get("Cookie")); final boolean sessionPassed=db.sessionCheck(cookie); System.out.println("Cookie: "+cookie); System.out.println("Session passed?: "+sessionPassed); final String user_i=cookie.get("rmbdI"); if (user_i!=null) { try { ResultSet user=db.findUserByIndex(Long.parseLong(user_i, 16)); if (user.next()) { System.out.println("User ID: "+user.getString("id")); } } catch (SQLException e) { db.err(e); } } String tmpLang=req.params().get("lang"); if (tmpLang==null) { tmpLang=cookie.get("lang"); if (tmpLang==null) { tmpLang="en"; } } final String lang=tmpLang; System.out.println("Lang: "+lang); String[] pathSplit=path.split("/"); if (pathSplit.length<=1) { // path=/ if (cookie.get("I")!=null||cookie.get("rmbdI")!=null) { req.response().putHeader("Content-Type", "text/html; charset=utf-8"); req.response().end(FileMapWithVar.get("user-page.html", lang, db.varMapMyPage(cookie)), ENCODING); System.out.println("Sended user-page.html"); } else { req.response().putHeader("Content-Type", "text/html; charset=utf-8"); req.response().end(FileMap.get("to-log-in.html", lang), ENCODING); // window.location.pathname="/account/log-in"; System.out.println("Sended to-log-in.html"); // redirecting to /account/log-in since rmbd cookie is to be checked too. } } else if (pathSplit.length==2) { // e.g. path=/jquery.min.js if (refererAllowed) { switch (pathSplit[1]) { case "sessionIter": // e.g. path=/sessionIter String iter=db.sessionIter(cookie); req.response().putHeader("Content-Type", "text/plain"); req.response().end(iter); System.out.println("iter: "+iter); break; case "reco": // e.g. path=/reco if (cookie.get("rmbdI")!=null) { req.response().putHeader("Content-Type", "text/html; charset=utf-8"); req.response().end(FileMapWithVar.get("user-page.html", lang, db.varMapMyPage(cookie)), ENCODING); System.out.println("Sended user-page.html. URI [?search] will be handled by javascript."); } else { req.response().putHeader("Content-Type", "text/html; charset=utf-8"); req.response().end(FileMap.get("to-log-in.html", lang), ENCODING); // window.location.href="/account/log-in?goto="+encodeURIComponent(fullPath); System.out.println("Sended to-log-in.html."); // redirecting to /account/log-in since rmbd cookie is to be checked too. } break; case "favicon.ico": // e.g. path=/favicon.ico String fileName=FileMap.getCDNFile(pathSplit[1]); req.response().putHeader("Content-Type","image/x-icon"); req.response().sendFile(fileName); System.out.println("Sended "+fileName+"."); break; case "jquery.min.js": // e.g. path=/jquery.min.js req.response().putHeader("Content-Type","text/javascript"); req.response().end(FileMap.get("jquery.min.js", "df"), ENCODING); System.out.println("Sended jquery.min.js."); break; case "robots.txt": // e.g. path=/robots.txt req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(FileMap.get("robots.txt", "df"), ENCODING); System.out.println("Sended robots.txt."); break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS); }}} else if (pathSplit.length>2) { switch (pathSplit[1]) { case "user": // e.g. path=/user/kipid/mode/multireco?cat=... String user=URLDecoder.decode(pathSplit[2]); if (pathSplit.length==3||pathSplit.length==5) { // e.g. path=/user/kipid[/mode/multireco]?cat=... if (db.idExists(user)) { req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMapWithVar.get("user-page.html", lang, db.varMapUserPage(cookie, user)), ENCODING); System.out.println("Sended user-page.html"); } else { String res=FileMap.replaceStr("<h1>[--User does not exist.--]</h1>", lang); req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(res, ENCODING); System.out.println("Sended '"+res+"'"); } } else if (pathSplit.length==4&&method==HttpMethod.POST) { // e.g. path=/user/kipid/get-Recos switch (pathSplit[3]) { case "get-Recos": // e.g. path=/user/kipid/get-Recos req.bodyHandler((Buffer data) -> { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(db.getRecos(user, new StrArray(data.toString())), ENCODING); System.out.println("Sended recos."); }); break; case "get-UriList": // e.g. path=/user/kipid/get-UriList req.bodyHandler((Buffer data) -> { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(db.getStringCatUriList(user, new StrArray(data.toString())), ENCODING); System.out.println("Sended uriLists."); }); break; // case "get-Neighbors": // e.g. path=/user/kipid/get-Neighbors // req.bodyHandler((Buffer data) -> { // req.response().putHeader("Content-Type","text/plain; charset=utf-8"); // req.response().end(db.getStrOfNeighbors(user, new StrArray(data.toString())), ENCODING); // System.out.println("Sended neighbors."); // }); // break; // case "/get-URI-cats-val": // e.g. path=/user/kipid/get-URI-cats-val // req.bodyHandler((Buffer data) -> { // req.response().putHeader("Content-Type","text/plain; charset=utf-8"); // req.response().end(db.getUriCatsVal(user, new StrArray(data.toString())), ENCODING); // System.out.println("Sended URI-cats-val."); // }); // break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS); } } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid method: "+method+")"); } break; case "CDN": // e.g. path=/CDN/icon-Recoeve.png if (refererAllowed) { // e.g. path=/CDN/docuK-prepare-2.3.js String fileName=FileMap.getCDNFile(pathSplit[2]); if (fileName!=null) { String[] fileNameSplit=pathSplit[2].split("\\."); switch (fileNameSplit[fileNameSplit.length-1]) { case "ico": req.response().putHeader("Content-Type","image/x-icon"); break; case "png": req.response().putHeader("Content-Type","image/png"); break; case "jpeg": case "jpg": req.response().putHeader("Content-Type","image/jpeg"); break; case "css": req.response().putHeader("Content-Type","text/css; charset=utf-8"); break; case "js": req.response().putHeader("Content-Type","text/javascript; charset=utf-8"); break; case "webm": req.response().putHeader("Content-Type","video/webm"); break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); } req.response().sendFile(fileName); System.out.println("Sended "+fileName+"."); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (No file.)"); } } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Referer not allowed.)"); } break; case "reco": // e.g. path=/reco/do if (refererAllowed&&method==HttpMethod.POST) { switch (pathSplit[2]) { case "defs": // path=/reco/defs req.bodyHandler((Buffer data) -> { final String uri=data.toString(); String res=db.recoDefs(uri); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res); System.out.println("Sended defs of uri="+uri+"."); }); break; case "do": // path=/reco/do if (sessionPassed) { req.bodyHandler((Buffer data) -> { final String recoStr=data.toString(); String res=db.recoDo(Long.parseLong(cookie.get("I"), 16), recoStr); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res); System.out.println("Do reco:\n"+recoStr); }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("No session."); System.out.println("No session."); } break; case "put": // path=/reco/put if (sessionPassed) { req.bodyHandler((Buffer data) -> { final String recoStr=data.toString(); String res=db.putReco(Long.parseLong(cookie.get("I"), 16), recoStr); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res); System.out.println("Put reco:\n"+recoStr); }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("No session."); System.out.println("No session."); } break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid URI.)"); } } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Referer not allowed, or method: "+method+")"); } break; case "account": // e.g. path=/account/... if (refererAllowed) { switch (pathSplit[2]) { case "changePwd": // path=/account/changePwd if (db.checkChangePwdToken(req.params(), now)) { req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMap.get("changePwd.html", lang), ENCODING); System.out.println("Sended changePwd.html."); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS); } break; case "getNewSalt": // path=/account/getNewSalt if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { final String dataStr=data.toString(); int i=dataStr.indexOf("\t"); if (i>0) { String id=dataStr.substring(0,i); String token=dataStr.substring(i+1); if (db.checkChangePwdToken(id, token, now)) { String new_salt=db.getNewPwdSalt("id", id); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(new_salt, ENCODING); System.out.println("Sended new password_salt: "+new_salt+"."); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Invalid token.", ENCODING); System.out.println("Invalid token."); } } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid form: no tab)"); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid method: "+method+")"); } break; case "changePwd.do": // path=/account/changePwd.do if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { BodyData inputs=new BodyData(data.toString()); System.out.println("data:\n"+inputs); if (db.checkChangePwdToken(inputs.get("userId"), inputs.get("token"), now)) { System.out.println("Token is verified. User ID: "+inputs.get("userId")); if (db.changePwd(inputs, ip, now)) { final String res=FileMap.replaceStr("[--Your password is changed.--]", lang); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res, ENCODING); System.out.println("Sended "+res); } else { final String res=FileMap.replaceStr("[--Error occured during changing password. Please try again.--]", lang); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res, ENCODING); System.out.println("Sended "+res); } } else { final String res=FileMap.replaceStr("[--Token is invalid.--]", lang); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res, ENCODING); System.out.println("Sended "+res); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid method: "+method+")"); } break; case "log-in": // path=/account/log-in if (pathSplit.length==3) { if (sessionPassed) { req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMapWithVar.get("user-page.html", lang, db.varMapMyPage(cookie)), ENCODING); System.out.println("Sended user-page.html. (already logged-in)"); } else if (cookie.get("rmbdI")!=null) { req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMap.get("remember-me.html", lang), ENCODING); System.out.println("Sended remember-me.html."); } else { req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMap.get("log-in.html", lang), ENCODING); System.out.println("Sended log-in.html. (No rmbd cookie)"); } } else { switch (pathSplit[3]) { case "remember-me.do": // path=/account/log-in/remember-me.do if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { StrArray inputs=new StrArray(data.toString()); List<io.vertx.core.http.Cookie> setCookieRMB=db.authUserFromRmbd(cookie, inputs, ip); for (io.vertx.core.http.Cookie singleCookie: setCookieRMB) { req.response().addCookie(singleCookie); System.out.println(singleCookie.getName()+": "+singleCookie.getValue()); } if (setCookieRMB.get(0).getName()=="I") { // Success: Session cookie and New token. req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Rmbd", ENCODING); System.out.println("Sended Rmbd with Set-Cookie of session and new rmbd token. (Succeed in remembering the user.)"); } else { // if (setCookieRMB.startsWith("rmbdI=")) // Failed: Delete rmbd cookie. req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Remembering you failed.", ENCODING); System.out.println("Sended 'Failed' with Set-Cookie of deleting rmbd cookie. (Fail in remembering the user.)"); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid method: "+method+")"); } break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid URI.)"); }} break; case "pwd_iteration": // path=/account/pwd_iteration if (sessionPassed) { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("pwd_iteration: You are already logged in Recoeve.", ENCODING); System.out.println("Sended 'You are already logged in Recoeve.'"); } else if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { String dataStr=data.toString(); int i=dataStr.indexOf("\t"); if (i>0) { String idType=dataStr.substring(0,i); String id=dataStr.substring(i+1); String iter=db.getPwdIteration(idType, id); req.response().end(iter, ENCODING); System.out.println("Sended pwd_iteration for "+idType+" "+id+": "+iter); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Invalid form of data (no tab).", ENCODING); System.out.println("Invalid form of data (no tab). dataStr: "+dataStr); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid method: "+method+")"); } break; case "log-in.do": // path=/account/log-in.do if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { StrArray inputs=new StrArray(data.toString()); List<io.vertx.core.http.Cookie> setCookieSSN=db.authUser(inputs, ip); if (setCookieSSN!=null) { // Log-in success! for (io.vertx.core.http.Cookie singleCookie: setCookieSSN) { req.response().addCookie(singleCookie); } req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("log-in success", ENCODING); System.out.println("Sended log-in success: "+inputs.get(1, "idType")+": "+inputs.get(1, "userId")); } else { // Log-in failed. req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("log-in fail", ENCODING); System.out.println("log-in fail: "+inputs.get(1, "idType")+": "+inputs.get(1, "userId")); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid method: "+method+")"); } break; case "log-out": // path=/account/log-out List<io.vertx.core.http.Cookie> setDelCookie=db.logout(cookie); for (io.vertx.core.http.Cookie singleCookie: setDelCookie) { req.response().addCookie(singleCookie); } req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMap.get("log-in.html", lang), ENCODING); System.out.println("Sended log-in.html with Set-Cookie of deleting all cookies."); break; case "check": // path=/account/check if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { String dataStr=data.toString(); int i=dataStr.indexOf("\t"); String id=dataStr.substring(0,i); String email=dataStr.substring(i+1); boolean idAvailable=db.idAvailable(id); boolean emailAvailable=db.emailAvailable(email); System.out.println("Checking: "+id+" and "+email); System.out.println("Availability: "+idAvailable+"\t"+emailAvailable); if (idAvailable&&emailAvailable) { byte[] token=db.randomBytes(128); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end( idAvailable+"\t"+emailAvailable+"\t"+(db.createAuthToken(now, ip, token)?now+"\t"+db.hex(token):"Token is not created.") , ENCODING); System.out.println("Both ID: "+id+" and email: "+email+" are available. So a token is created."); } else { db.logsCommit(1 // `user_i`=1 for anonymous. , now, ip, "chk", false, "ID: "+id+" ["+idAvailable+"] and E-mail: "+email+" ["+emailAvailable+"] availability check."); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end( idAvailable+"\t"+emailAvailable , ENCODING); System.out.println("ID: "+id+" is available? "+idAvailable+", and email: "+email+" is available? "+emailAvailable); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println("check: invalid method "+method); } break; case "forgotPwd": // path=/account/forgotPwd if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { StrArray inputs=new StrArray(data.toString()); String forgotPwd=db.forgotPwd(inputs, lang); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(forgotPwd, ENCODING); System.out.println("Sended forgotPwd: "+forgotPwd); }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println("forgotPwd: invalid method "+method); } break; case "sign-up": // path=/account/sign-up if (method==HttpMethod.POST) { req.bodyHandler((Buffer data) -> { StrArray inputs=new StrArray(data.toString()); if (db.checkAuthToken(inputs, ip, now)) { System.out.println("Token is verified."); if (db.createUser(inputs, ip, now)) { Map<String,String> varMap=new HashMap<String,String>(); varMap.put("{--user id--}", inputs.get(1, "userId")); varMap.put("{--user email--}", inputs.get(1, "userEmail")); req.response().putHeader("Content-Type","text/html; charset=utf-8"); req.response().end(FileMapWithVar.get("signed-up.html", lang, varMap), ENCODING); System.out.println("Sended signed-up.html."); } else { final String res=FileMap.replaceStr("[--Error occured during registration. Please sign-up again.--]", lang); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(res, ENCODING); System.out.println("Sended "+res); } } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Token is invalid.", ENCODING); System.out.println("Token is invalid."); } }); } else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println("sign-up: invalid method "+method); } break; case "verify": // path=/account/verify/.....token if (sessionPassed) { // VeriKey check. if (db.verifyUser(cookie.get("I"), URLDecoder.decode(pathSplit[3]), ip)) { // User is verified. req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("You are verified.", ENCODING); System.out.println("Sended 'You are verified.'."); } else { // User is NOT verified. req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Wrong verification key.", ENCODING); System.out.println("Sended 'Wrong verification key.'."); } } else { // Log-in 유도. req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end("Please log in first to verify your account.", ENCODING); System.out.println("Sended 'Please log in first to verify your account.'."); } default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid URI/path.)"); }} else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Referer not allowed.)"); } break; case "changeOrders": // e.g. path=/changeOrders/CatList if (refererAllowed&&sessionPassed&&method==HttpMethod.POST) { switch (pathSplit[2]) { case "CatList": req.bodyHandler((Buffer data) -> { final boolean res=db.changeOrdersCatList(Long.parseLong(cookie.get("I"), 16), data.toString()); req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(""+res); System.out.println("Result: "+res); }); break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid URI/path.)"); }} else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Referer not allowed, or not sessionPassed, or invalid method: "+method+")"); } break; default: req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid URI.)"); }} else { req.response().putHeader("Content-Type","text/plain; charset=utf-8"); req.response().end(INVALID_ACCESS, ENCODING); System.out.println(INVALID_ACCESS+" (Invalid path.)"); } }); vertx.createHttpServer( new HttpServerOptions() .setUseAlpn(true) .setSsl(true) .setKeyStoreOptions(new JksOptions() .setPath("C:/Recoeve/recoeve.jks") .setPassword("Kd8#j$LL0@OM1") ) ).requestHandler(router).listen(443); vertx.createHttpServer() .requestHandler(router).listen(80); } // public void start() } // public class Recoeve extends AbstractVerticle ```/
## RRA

    Official

  1. groups.google.com - vertx
  2. Vert.x.io and http://vertx.io - docs
  3. github.com - vert-x3
    Old version :: github.com - vert-x; and the main project github.com - eclipse - vert.x
  4. vertx-kor.otofu.me; Official homepage는 아닌가? 최신 정보를 위해서는 영어 페이지로 봅시다.
  5. Introducing

  6. Naver 개발자 블로그 Hello world - vert.x는 무엇이 좋은가?, 2012-10-05, by 우성민
  7. Naver 개발자 블로그 Hello world - vert.x 임베디드, 2013-05-13, by 김재홍
    // Embeded 형태로도 vert.x 를 쓸 수 있구나. Spring MVC 같은데에 vert.x 를 embed 해서 사용할 수 있다는듯. 그런데 이러면 vert.x 의 performance 를 해치는거 같기도 한데... 잘 모르겄넹;;
  8. Daum DevOn 2012 - B3 자바기반 Vert.x로 Socket.io 서버 만들기, 2012-10-12, by 백기선 (NHN Business Platform); 영상 (42 min) 도 있음.
    // Socket.io 괜찮아 보이는데 "facebook post by Keesun Baik, 2013-12-17" 에서는 "한동안 Socket.io + Vert.x로 재미를 봤었는데.. 이제 그거 그만 쓰는게 좋을것 같다. 이제는 스프링 4가 하듯이 Websocket은 전송수단으로 쓰고 STOMP라는 훌륭한 메시징 프로토콜(+구현체)을 그 위에 얹어서 쓰는게 좋겠다."라고 하시기도...
  9. bcho.tistory.com - 비동기 네트워크 서버 프레임웍 Vert.x 소개, 2014-02-04, by 조대협
  10. Competition with other server-side languages

  11. Tech Empower.com - Web Framework Benchmarks - Round 21 (2022-07-19) - Composite scores
    // 11위 vert.x, 19위 vert.x-web. 성적 좋아진듯 예전보다. 괜찮네.
  12. vertxproject.wordpress.com - Vert.x vs node.js simple HTTP benchmarks, 2012-05-09, by swilliamsvmw;
    // Node.js와 비교해봤을때 훨씬 더 뛰어나다는 이야기. 그중 Vert.x Java를 쓰는것이 가장 성능이 좋은듯. 당연한 결과 같기도... 배우려면 vert.x Java를 배웁시다? 엄밀히는 Java에서 vert.x library를 쓰는 개념이겠지만.
  13. kipid's blog - Learning Node.js, 2014-05-23;
    // Event-driven server의 특징을 보시려면, 여기로 가보시면 될듯. Node.js를 쓰지는 않더라도 개념을 이해해놓으면 여러모로 도움이 되는듯.
  14. Example

  15. https://github.com/kipid/Recoeve
  16. [Music/Break]--K-Pop of kipid's Recoeve.net
반응형