Giter Site home page Giter Site logo

cettia / asity Goto Github PK

View Code? Open in Web Editor NEW
25.0 7.0 1.0 1.06 MB

Build universally reusable web fragments on the JVM

Home Page: https://asity.cettia.io/

License: Apache License 2.0

Java 99.83% Scala 0.17%
websockets java jvm http framework-agnostic asynchronous abstraction-layer web-framework web-fragment

asity's Introduction

Asity

Asity is an HTTP/WebSocket abstraction layer for various web frameworks on the JVM. Asity provides a tool-kit for writing a web fragment, a function that handles HTTP request-response exchange and WebSocket, and allows to create web applications by combining web fragments.

For example, with Asity you can write a web fragment that sends back incoming WebSocket messages as follows

Action<ServerWebSocket> action = ws -> ws.ontext(ws::send).onbinary(ws::send);

And plug it into Java API for WebSocket, Spring WebFlux, Spring MVC, Vert.x, Netty, Play Framework, Grizzly, and so on. Visit the Asity website for the full documentation.

Supported Frameworks

Asity supports the following frameworks. Each link points to a demo project which shows how to plug the example echo web fragment to each framework.

Links

Here are some useful links to learn more about Asity. If you are interested and would like to be more involved, feel free to join the mailing list and share your feedback.

Asity is an open source project licensed under Apache License 2.0 and driven by the community, for the community.

asity's People

Contributors

dependabot[bot] avatar flowersinthesand avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

asity's Issues

Don't use dependencyManagement for framework dependencies

Asity has to manage multiple versions of the same dependency, e.g. org.springframework.boot:spring-boot-starter:2.0.2.RELEASE for spring-webflux5 and org.springframework.boot:spring-boot-starter:1.5.13.RELEASE for spring-webmvc4, unlike a typical Maven project. If given org.springframework.boot:spring-boot-starter as a dependency declaration, it's difficult to infer its version and likely to be error-prone in some way.

Therefore, it's better to declare <dependency> with its version as needed instead of <dependencyManagement>, in bridge and example projects.

Add working examples

The current bridge's test cases execute unit tests by embedding the framework and starting it up programmatically, but this way is a little bit far from the framework's instructions. We need to guide various ways per framework to plug given arbitrary web fragments into the framework according to the framework's instructions for the newbies to learn Asity with ease.

  • Use Maven only for the sake of easy maintenance.
  • Place example web fragments in an io.cettia.asity:asity-example project's an io.cettia.asity.example.xxx package. For now, the echo example should be enough.
  • Create a dedicated maven project per bridge e.g. io.cettia.asity:asity-example-vertx3
  • Use a browser as a runtime to run counterpart client examples and host examples on JS Bin.

HTTP header name should be returned in lowercase

For the same request, its header may vary according to the underlying platform in terms of case sensitivity. Header has nothing to do with case sensitivity and it doesn't matter at the level of HTTP 1.1 speicification. But, in Java, header is represented as String and it does matter.

// Assumes the same request sent to Servlet and Netty
assertEquals(httpByServlet.headerNames(), httpByNetty.headerNames());

At least, the above assertion should pass. To do that, Every header in returned a set of header string should be lower cased.

Play framework doesn't set the content-type header

To reproduce the bug, run the example-play2 and send the following curl command. As you can see, there's no content-type header in the response.

➜  bridge-play2 git:(master) ✗ curl -v -X POST -H 'Content-Type: text/html; charset=utf-8' -d 'A message to be sent back' http://localhost:8080/echo
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /echo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: text/html; charset=utf-8
> Content-Length: 25
> 
* upload completely sent off: 25 out of 25 bytes
< HTTP/1.1 200 OK
< Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
< X-Frame-Options: DENY
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Permitted-Cross-Domain-Policies: master-only
< Date: Sat, 29 Jun 2019 12:26:15 GMT
< Transfer-Encoding: chunked
< 
* Connection #0 to host localhost left intact
A message to be sent back%                                                                                                                                                    

Here's the cause:

21:26:15.697 WARN [play-dev-mode-akka.actor.default-dispatcher-13] a.a.ActorSystemImpl [Slf4jLogger.scala:86] Explicitly set HTTP header 'Content-Type: text/html; charset=UTF-8' is ignored, explicit `Content-Type` header is not allowed. Set `HttpResponse.entity.contentType` instead.

The following is the correct result using example-spring-webmvc4. The content-type response header is Content-Type: text/html;charset=utf-8.

➜  bridge-play2 git:(master) ✗ curl -v -X POST -H 'Content-Type: text/html; charset=utf-8' -d 'A message to be sent back' http://localhost:8080/echo
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /echo HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: text/html; charset=utf-8
> Content-Length: 25
> 
* upload completely sent off: 25 out of 25 bytes
< HTTP/1.1 200 
< Content-Type: text/html;charset=utf-8
< Transfer-Encoding: chunked
< Date: Sat, 29 Jun 2019 12:28:08 GMT
< 
* Connection #0 to host localhost left intact
A message to be sent back%                                                                                                                                                    

Write a spec to test read request body by chunk asynchronously

Some I/O frameworks such as Servlet 3.0 containers and Atmosphere 2 wrapping them don't allow to read request body asynchronously even though request uses the chunked transfer encoding, transfer-encoding: chunked.

We will drop supports for these frameworks in the next major version.

Rewrite tests

To conform to a common naming convention and improve usability of asity-test module.

Use Enum to represent the HTTP request method

In general, Enum is preferred to String when representing a set of constants. At first I used String as the request method is customizable according to the spec but only a few names has been used in practice when writing an web application.

According to Hypertext Transfer Protocol (HTTP) Method Registry, only GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE and PATCH are concerned. (PRI is for HTTP 2 and The rest are for WebDAV, which are not suitable for Asity)

Netty 4.1 support

According to http://netty.io/wiki/new-and-noteworthy-in-4.1.html, Netty 4.1 is not fully backward-compatible with 4.0. After upgrading Netty from 4.0 to 4.1, I found that unit tests of Netty bridge fail.

Since its major version is still 4, I don't want to create a new module for only 4.1. Let's try to resolve it within only one module by leveraging reflection.

Prepare for Asity 2.0.0

Asity 2.0.0 requires Java 8 or above.

  • Update .travis.yml.
  • Replace anonymous type with lambda expression.
  • Replace lambda expression with method reference.
  • Update dependencies.
  • Update plugins.
  • Update Javadoc links.

Fix Vert.x unit test failures

I found that 481d142 doesn't pass even in my macbook. By setting Jetty client's log level to DEBUG, it turns out that a client couldn't establish a connection.

It can be fixed by making sure the server completes the startup process.

CountDownLatch latch = new CountDownLatch(1);
server.listen(port, ar -> latch.countDown());
latch.await();

Support Spring Web MVC

Spring Web MVC is a web framework of Spring's servlet stack following Java BluePrints. Well I remember discussion on which web framework we should use among Struts 1, 2 and Spring MVC 2 almost 10 years ago ;)

For a broader coverage, we will use Spring Web MVC 4.

Delegate thread management to I/O framework

According to the design philosophy, Asity shouldn't get involved in thread management to enable end users to have a full control of framework they use. However, some bridges now create and run a thread for some reason.

At least, they should delegate thread management to underlying I/O framework by submitting a task to the I/O framework's thread pool.

Spring Boot startup takes too long

At least in my local machine, mvn test takes too long. spring-webflux (10:27 min) and spring-webmvc (08:21 min) account for 93% of the total time (20:15 min).

[INFO] Reactor Summary:
[INFO] 
[INFO] Asity 3.0.0-Beta2-SNAPSHOT ......................... SUCCESS [  0.517 s]
[INFO] Asity/Action ....................................... SUCCESS [  2.521 s]
[INFO] Asity/HTTP ......................................... SUCCESS [  2.402 s]
[INFO] Asity/WebSocket .................................... SUCCESS [  0.055 s]
[INFO] Asity/Test ......................................... SUCCESS [  0.139 s]
[INFO] Asity/Bridge/Atmosphere 2 .......................... SUCCESS [  6.885 s]
[INFO] Asity/Bridge/Grizzly 2 ............................. SUCCESS [  3.987 s]
[INFO] Asity/Bridge/Java WebSocket API 1 .................. SUCCESS [  3.497 s]
[INFO] Asity/Bridge/Netty 4 ............................... SUCCESS [  9.904 s]
[INFO] Asity/Bridge/Play Framework 2 ...................... SUCCESS [  0.370 s]
[INFO] Asity/Bridge/Servlet 3 ............................. SUCCESS [  4.438 s]
[INFO] Asity/Bridge/Spring WebFlux 5 ...................... SUCCESS [10:27 min]
[INFO] Asity/Bridge/Spring Web MVC 4 ...................... SUCCESS [08:21 min]
[INFO] Asity/Bridge/Vert.x 2 .............................. SUCCESS [  3.999 s]
[INFO] Asity/Bridge/Vert.x 3 .............................. SUCCESS [  9.638 s]
[INFO] Asity/Example ...................................... SUCCESS [  0.294 s]
[INFO] Asity/Example/Atmosphere 2 ......................... SUCCESS [  0.130 s]
[INFO] Asity/Example/Grizzly 2 ............................ SUCCESS [  0.177 s]
[INFO] Asity/Example/Java WebSocket API 1 ................. SUCCESS [  0.092 s]
[INFO] Asity/Example/Netty 4 .............................. SUCCESS [  0.056 s]
[INFO] Asity/Example/Play framework 2 ..................... SUCCESS [ 33.688 s]
[INFO] Asity/Example/Servlet 3 ............................ SUCCESS [  0.039 s]
[INFO] Asity/Example/Spring WebFlux 5 ..................... SUCCESS [  0.179 s]
[INFO] Asity/Example/Spring Web MVC 4 ..................... SUCCESS [  0.108 s]
[INFO] Asity/Example/Vert.x 2 ............................. SUCCESS [  1.617 s]
[INFO] Asity/Example/Vert.x 3 3.0.0-Beta2-SNAPSHOT ........ SUCCESS [  0.144 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 20:15 min
[INFO] Finished at: 2019-06-26T21:53:15+09:00
[INFO] ------------------------------------------------------------------------
➜

OutOfMemoryError thrown when testing Netty on Travis CI

On my desktop where Windows 8.1 64 bit and Java 7u55 are installed and Windows 10 64 bit and Java 7u71, it has never happened so I'm not sure how I should approach the issue.

Here is log:

The error's typical stack trace looks like:

13:27:55.475 WARN [Time-limited test] i.n.c.AbstractChannel [Slf4JLogger.java:146] Force-closing a channel whose registration task was not accepted by an event loop: [id: 0x93ff02c4]
java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method) [na:1.7.0_76]
    at java.lang.Thread.start(Thread.java:714) [na:1.7.0_76]
    at io.netty.util.concurrent.SingleThreadEventExecutor.startThread(SingleThreadEventExecutor.java:853) ~[netty-common-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:727) ~[netty-common-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.channel.AbstractChannel$AbstractUnsafe.register(AbstractChannel.java:420) ~[netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:60) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.channel.SingleThreadEventLoop.register(SingleThreadEventLoop.java:48) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.channel.MultithreadEventLoopGroup.register(MultithreadEventLoopGroup.java:64) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:317) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.bootstrap.AbstractBootstrap.doBind(AbstractBootstrap.java:273) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:269) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:244) [netty-transport-4.0.25.Final.jar:4.0.25.Final]
    at io.cettia.platform.bridge.netty4.NettyServerWebSocketTest.startServer(NettyServerWebSocketTest.java:76) [test-classes/:na]
    at io.cettia.platform.test.ServerWebSocketTest.before(ServerWebSocketTest.java:58) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_76]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_76]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_76]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_76]
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12]
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12]
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) [junit-4.12.jar:4.12]
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) [junit-4.12.jar:4.12]
    at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298) [junit-4.12.jar:4.12]
    at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292) [junit-4.12.jar:4.12]
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_76]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_76]

Allow to read WebSocket handshake request headers

The WebSocket interface specified by W3C and available in browsers doesn't allow to set request headers but in some cases request headers are used and can be configured. For example, subprotocol names are transmitted through Sec-WebSocket-Protocol header field. Also, this restriction is only valid in browser-based applications.

This feature allows to read WebSocket handshake request headers without unwrapping a ServerWebSocket instance to access underlying objects so that a developer should be able to retrieve headers such as Authorization and Sec-WebSocket-Protocol and use them to implement some protocol.

The following methods will be added in ServerWebSocket as handshake request header accessors:

  • Set<String> headerNames();
  • String header(String name);
  • List<String> headers(String name);

Support Micronaut

Micronaut

Micronaut features a Dependency Injection and Aspect-Oriented Programming runtime that uses no reflection. It runs on Netty.

Use different path for HTTP and WebSocket test

In some frameworks like Play it's picky to use the same path for HTTP handler and WebSocket handler. This feature streamlines this problem by allowing test class to customize the test endpoint's path. by using different endpoint path for HTTP and WebSocket test.

  • Set ServerHttpExchangeTestBase's TEST_URI to /http
  • Set ServerWebSocketTestBase's TEST_URI to /websocket
  • Make their TEST_URI constant public
  • Rename TEST_URI to TEST_PATH

Fail to generate Javadoc

I got the following error log:

asity git:(master) ✗ mvn javadoc:aggregate

Skipped ...

46 errors
100 warnings
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Asity 2.0.0-SNAPSHOT ............................... FAILURE [ 11.323 s]
[INFO] Asity/Action ....................................... SKIPPED
[INFO] Asity/HTTP ......................................... SKIPPED
[INFO] Asity/WebSocket .................................... SKIPPED
[INFO] Asity/Test ......................................... SKIPPED
[INFO] Asity/Bridge/Atmosphere 2 .......................... SKIPPED
[INFO] Asity/Bridge/Grizzly 2 ............................. SKIPPED
[INFO] Asity/Bridge/Java WebSocket API 1 .................. SKIPPED
[INFO] Asity/Bridge/Netty 4 ............................... SKIPPED
[INFO] Asity/Bridge/Servlet 3 ............................. SKIPPED
[INFO] Asity/Bridge/Spring WebFlux 5 ...................... SKIPPED
[INFO] Asity/Bridge/Vert.x 2 2.0.0-SNAPSHOT ............... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.931 s
[INFO] Finished at: 2018-05-23T20:39:31+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:3.0.0:aggregate (default-cli) on project asity-parent: An error has occurred in Javadoc report generation: 
[ERROR] Exit code: 1 - /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/VoidAction.java:26: warning: '_' used as an identifier
[ERROR]   public void on(Void _) {
[ERROR]                       ^
[ERROR]   (use of '_' as an identifier might not be supported in releases after Java SE 8)
[ERROR] javadoc: warning - Error fetching URL: http://vertx.io/vertx2/api/java/
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:30: warning: no @param for action
[ERROR]   Actions<T> add(Action<T> action);
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:30: warning: no @return
[ERROR]   Actions<T> add(Action<T> action);
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:36: warning: no @return
[ERROR]   Actions<T> disable();
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:41: warning: no @return
[ERROR]   boolean disabled();
[ERROR]           ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:46: warning: no @return
[ERROR]   Actions<T> empty();
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:51: warning: no @return
[ERROR]   Actions<T> fire();
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:56: warning: no @param for data
[ERROR]   Actions<T> fire(T data);
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:56: warning: no @return
[ERROR]   Actions<T> fire(T data);
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:61: warning: no @return
[ERROR]   boolean fired();
[ERROR]           ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:66: warning: no @return
[ERROR]   boolean has();
[ERROR]           ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:71: warning: no @param for action
[ERROR]   boolean has(Action<T> action);
[ERROR]           ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:71: warning: no @return
[ERROR]   boolean has(Action<T> action);
[ERROR]           ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:76: warning: no @param for action
[ERROR]   Actions<T> remove(Action<T> action);
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:76: warning: no @return
[ERROR]   Actions<T> remove(Action<T> action);
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Action.java:28: warning: no @param for object
[ERROR]   void on(T object);
[ERROR]        ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:20: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:107: warning: no @param for once
[ERROR]     public Options once(boolean once) {
[ERROR]                    ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:107: warning: no @return
[ERROR]     public Options once(boolean once) {
[ERROR]                    ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:121: warning: no @param for memory
[ERROR]     public Options memory(boolean memory) {
[ERROR]                    ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:121: warning: no @return
[ERROR]     public Options memory(boolean memory) {
[ERROR]                    ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:133: warning: no @param for unique
[ERROR]     public Options unique(boolean unique) {
[ERROR]                    ^
[ERROR] /Users/donghwankim/git/asity/action/src/main/java/io/cettia/asity/action/Actions.java:133: warning: no @return
[ERROR]     public Options unique(boolean unique) {
[ERROR]                    ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:38: warning: no @return
[ERROR]   String uri();
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:43: warning: no @return
[ERROR]   HttpMethod method();
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:49: warning: no @return
[ERROR]   Set<String> headerNames();
[ERROR]               ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:54: warning: no @param for name
[ERROR]   String header(String name);
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:54: warning: no @return
[ERROR]   String header(String name);
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:60: warning: no @param for name
[ERROR]   List<String> headers(String name);
[ERROR]                ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:60: warning: no @return
[ERROR]   List<String> headers(String name);
[ERROR]                ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:67: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:71: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:78: warning: no @return
[ERROR]   ServerHttpExchange read();
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:84: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:87: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:94: warning: no @return
[ERROR]   ServerHttpExchange readAsText();
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:98: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:101: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:108: warning: no @param for charsetName
[ERROR]   ServerHttpExchange readAsText(String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:108: warning: no @return
[ERROR]   ServerHttpExchange readAsText(String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:112: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:115: error: self-closing element not allowed
[ERROR]    * <p/>
[ERROR]      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:122: warning: no @return
[ERROR]   ServerHttpExchange readAsBinary();
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:129: warning: no @param for action
[ERROR]   ServerHttpExchange onchunk(Action<?> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:129: warning: no @return
[ERROR]   ServerHttpExchange onchunk(Action<?> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:135: warning: no @param for action
[ERROR]   ServerHttpExchange onend(Action<Void> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:135: warning: no @return
[ERROR]   ServerHttpExchange onend(Action<Void> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:144: warning: no @param for action
[ERROR]   ServerHttpExchange onbody(Action<?> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:144: warning: no @return
[ERROR]   ServerHttpExchange onbody(Action<?> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:149: warning: no @param for status
[ERROR]   ServerHttpExchange setStatus(HttpStatus status);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:149: warning: no @return
[ERROR]   ServerHttpExchange setStatus(HttpStatus status);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:154: warning: no @param for name
[ERROR]   ServerHttpExchange setHeader(String name, String value);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:154: warning: no @param for value
[ERROR]   ServerHttpExchange setHeader(String name, String value);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:154: warning: no @return
[ERROR]   ServerHttpExchange setHeader(String name, String value);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:159: warning: no @param for name
[ERROR]   ServerHttpExchange setHeader(String name, Iterable<String> value);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:159: warning: no @param for value
[ERROR]   ServerHttpExchange setHeader(String name, Iterable<String> value);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:159: warning: no @return
[ERROR]   ServerHttpExchange setHeader(String name, Iterable<String> value);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:166: warning: no @param for data
[ERROR]   ServerHttpExchange write(String data);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:166: warning: no @return
[ERROR]   ServerHttpExchange write(String data);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:171: warning: no @param for data
[ERROR]   ServerHttpExchange write(String data, String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:171: warning: no @param for charsetName
[ERROR]   ServerHttpExchange write(String data, String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:171: warning: no @return
[ERROR]   ServerHttpExchange write(String data, String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:176: warning: no @param for byteBuffer
[ERROR]   ServerHttpExchange write(ByteBuffer byteBuffer);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:176: warning: no @return
[ERROR]   ServerHttpExchange write(ByteBuffer byteBuffer);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:183: warning: no @return
[ERROR]   ServerHttpExchange end();
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:190: warning: no @param for data
[ERROR]   ServerHttpExchange end(String data);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:190: warning: no @return
[ERROR]   ServerHttpExchange end(String data);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:196: warning: no @param for data
[ERROR]   ServerHttpExchange end(String data, String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:196: warning: no @param for charsetName
[ERROR]   ServerHttpExchange end(String data, String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:196: warning: no @return
[ERROR]   ServerHttpExchange end(String data, String charsetName);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:202: warning: no @param for byteBuffer
[ERROR]   ServerHttpExchange end(ByteBuffer byteBuffer);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:202: warning: no @return
[ERROR]   ServerHttpExchange end(ByteBuffer byteBuffer);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:208: warning: no @param for action
[ERROR]   ServerHttpExchange onfinish(Action<Void> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:208: warning: no @return
[ERROR]   ServerHttpExchange onfinish(Action<Void> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:215: warning: no @param for action
[ERROR]   ServerHttpExchange onerror(Action<Throwable> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:215: warning: no @return
[ERROR]   ServerHttpExchange onerror(Action<Throwable> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:222: warning: no @param for action
[ERROR]   ServerHttpExchange onclose(Action<Void> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:222: warning: no @return
[ERROR]   ServerHttpExchange onclose(Action<Void> action);
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:227: warning: no @param for <T>
[ERROR]   <T> T unwrap(Class<T> clazz);
[ERROR]         ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:227: warning: no @param for clazz
[ERROR]   <T> T unwrap(Class<T> clazz);
[ERROR]         ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:227: warning: no @return
[ERROR]   <T> T unwrap(Class<T> clazz);
[ERROR]         ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:302: warning: no @return
[ERROR]   public int code() {
[ERROR]              ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:309: warning: no @return
[ERROR]   public String reason() {
[ERROR]                 ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:316: warning: no @param for reason
[ERROR]   public HttpStatus newReason(String reason) {
[ERROR]                     ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:316: warning: no @return
[ERROR]   public HttpStatus newReason(String reason) {
[ERROR]                     ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:287: warning: no @param for code
[ERROR]   public HttpStatus(int code) {
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:294: warning: no @param for code
[ERROR]   public HttpStatus(int code, String reason) {
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/HttpStatus.java:294: warning: no @param for reason
[ERROR]   public HttpStatus(int code, String reason) {
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/http/src/main/java/io/cettia/asity/http/ServerHttpExchange.java:26: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:36: warning: no @return
[ERROR]   String uri();
[ERROR]          ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:47: warning: no @param for data
[ERROR]   ServerWebSocket send(String data);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:47: warning: no @return
[ERROR]   ServerWebSocket send(String data);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:52: warning: no @param for byteBuffer
[ERROR]   ServerWebSocket send(ByteBuffer byteBuffer);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:52: warning: no @return
[ERROR]   ServerWebSocket send(ByteBuffer byteBuffer);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:57: warning: no @param for action
[ERROR]   ServerWebSocket ontext(Action<String> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:57: warning: no @return
[ERROR]   ServerWebSocket ontext(Action<String> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:62: warning: no @param for action
[ERROR]   ServerWebSocket onbinary(Action<ByteBuffer> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:62: warning: no @return
[ERROR]   ServerWebSocket onbinary(Action<ByteBuffer> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:68: warning: no @param for action
[ERROR]   ServerWebSocket onclose(Action<Void> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:68: warning: no @return
[ERROR]   ServerWebSocket onclose(Action<Void> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:75: warning: no @param for action
[ERROR]   ServerWebSocket onerror(Action<Throwable> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:75: warning: no @return
[ERROR]   ServerWebSocket onerror(Action<Throwable> action);
[ERROR]                   ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:80: warning: no @param for <T>
[ERROR]   <T> T unwrap(Class<T> clazz);
[ERROR]         ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:80: warning: no @param for clazz
[ERROR]   <T> T unwrap(Class<T> clazz);
[ERROR]         ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:80: warning: no @return
[ERROR]   <T> T unwrap(Class<T> clazz);
[ERROR]         ^
[ERROR] /Users/donghwankim/git/asity/websocket/src/main/java/io/cettia/asity/websocket/ServerWebSocket.java:24: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:79: warning: no @param for resource
[ERROR]   protected boolean isWebSocketResource(AtmosphereResource resource) {
[ERROR]                     ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:79: warning: no @return
[ERROR]   protected boolean isWebSocketResource(AtmosphereResource resource) {
[ERROR]                     ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:90: warning: no @param for action
[ERROR]   public AsityAtmosphereServlet onhttp(Action<ServerHttpExchange> action) {
[ERROR]                                 ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:90: warning: no @return
[ERROR]   public AsityAtmosphereServlet onhttp(Action<ServerHttpExchange> action) {
[ERROR]                                 ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:39: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:40: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:42: error: semicolon missing
[ERROR]  * Servlet servlet = new AsityAtmosphereServlet().onhttp(http -&gt {}).onwebsocket(ws -&gt {});
[ERROR]                                                                ^
[ERROR] /Users/donghwankim/git/asity/bridge-atmosphere2/src/main/java/io/cettia/asity/bridge/atmosphere2/AsityAtmosphereServlet.java:42: error: semicolon missing
[ERROR]  * Servlet servlet = new AsityAtmosphereServlet().onhttp(http -&gt {}).onwebsocket(ws -&gt {});
[ERROR]                                                                                        ^
[ERROR] /Users/donghwankim/git/asity/bridge-grizzly2/src/main/java/io/cettia/asity/bridge/grizzly2/AsityHttpHandler.java:29: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-grizzly2/src/main/java/io/cettia/asity/bridge/grizzly2/AsityHttpHandler.java:30: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-grizzly2/src/main/java/io/cettia/asity/bridge/grizzly2/AsityHttpHandler.java:33: error: semicolon missing
[ERROR]  * config.addHttpHandler(new AsityHttpHandler().onhttp(http -&gt {}), "/cettia");
[ERROR]                                                              ^
[ERROR] /Users/donghwankim/git/asity/bridge-grizzly2/src/main/java/io/cettia/asity/bridge/grizzly2/AsityWebSocketApplication.java:33: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-grizzly2/src/main/java/io/cettia/asity/bridge/grizzly2/AsityWebSocketApplication.java:34: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-grizzly2/src/main/java/io/cettia/asity/bridge/grizzly2/AsityWebSocketApplication.java:39: error: semicolon missing
[ERROR]  * .onwebsocket(ws -&gt {}));
[ERROR]                     ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:30: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:31: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:37: error: semicolon missing
[ERROR]  *     protected &ltT&gt T getEndpointInstance(Class&ltT&gt endpointClass) throws
[ERROR]                  ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:37: error: semicolon missing
[ERROR]  *     protected &ltT&gt T getEndpointInstance(Class&ltT&gt endpointClass) throws
[ERROR]                      ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:37: error: semicolon missing
[ERROR]  *     protected &ltT&gt T getEndpointInstance(Class&ltT&gt endpointClass) throws
[ERROR]                                                     ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:37: error: semicolon missing
[ERROR]  *     protected &ltT&gt T getEndpointInstance(Class&ltT&gt endpointClass) throws
[ERROR]                                                         ^
[ERROR] /Users/donghwankim/git/asity/bridge-jwa1/src/main/java/io/cettia/asity/bridge/jwa1/AsityServerEndpoint.java:39: error: semicolon missing
[ERROR]  *         return endpointClass.cast(new AsityServerEndpoint().onwebsocket(ws -&gt {}));
[ERROR]                                                                                ^
[ERROR] /Users/donghwankim/git/asity/bridge-netty4/src/main/java/io/cettia/asity/bridge/netty4/AsityServerCodec.java:50: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-netty4/src/main/java/io/cettia/asity/bridge/netty4/AsityServerCodec.java:51: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-netty4/src/main/java/io/cettia/asity/bridge/netty4/AsityServerCodec.java:62: error: semicolon missing
[ERROR]  * .onhttp(http -&gt {}).onwebsocket(ws -&gt {}));
[ERROR]                  ^
[ERROR] /Users/donghwankim/git/asity/bridge-netty4/src/main/java/io/cettia/asity/bridge/netty4/AsityServerCodec.java:62: error: semicolon missing
[ERROR]  * .onhttp(http -&gt {}).onwebsocket(ws -&gt {}));
[ERROR]                                          ^
[ERROR] /Users/donghwankim/git/asity/bridge-servlet3/src/main/java/io/cettia/asity/bridge/servlet3/AsityServlet.java:32: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-servlet3/src/main/java/io/cettia/asity/bridge/servlet3/AsityServlet.java:33: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-servlet3/src/main/java/io/cettia/asity/bridge/servlet3/AsityServlet.java:35: error: semicolon missing
[ERROR]  * Servlet servlet = new AsityServlet().onhttp(http -&gt {});
[ERROR]                                                      ^
[ERROR] /Users/donghwankim/git/asity/bridge-spring-webflux5/src/main/java/io/cettia/asity/bridge/spring/webflux5/AsityHandlerFunction.java:29: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-spring-webflux5/src/main/java/io/cettia/asity/bridge/spring/webflux5/AsityHandlerFunction.java:30: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-spring-webflux5/src/main/java/io/cettia/asity/bridge/spring/webflux5/AsityHandlerFunction.java:36: error: bad use of '>'
[ERROR]  *     .and(headers(headers -> !"websocket".equalsIgnoreCase(headers.asHttpHeaders().getUpgrade()))),
[ERROR]                              ^
[ERROR] /Users/donghwankim/git/asity/bridge-spring-webflux5/src/main/java/io/cettia/asity/bridge/spring/webflux5/AsityWebSocketHandler.java:28: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-spring-webflux5/src/main/java/io/cettia/asity/bridge/spring/webflux5/AsityWebSocketHandler.java:29: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-vertx2/src/main/java/io/cettia/asity/bridge/vertx2/AsityRequestHandler.java:28: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-vertx2/src/main/java/io/cettia/asity/bridge/vertx2/AsityRequestHandler.java:29: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-vertx2/src/main/java/io/cettia/asity/bridge/vertx2/AsityRequestHandler.java:31: error: semicolon missing
[ERROR]  * httpServer.requestHandler(new AsityRequestHandler().onhttp(http -&gt {}));
[ERROR]                                                                     ^
[ERROR] /Users/donghwankim/git/asity/bridge-vertx2/src/main/java/io/cettia/asity/bridge/vertx2/AsityWebSocketHandler.java:27: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-vertx2/src/main/java/io/cettia/asity/bridge/vertx2/AsityWebSocketHandler.java:28: error: self-closing element not allowed
[ERROR]  * <p/>
[ERROR]    ^
[ERROR] /Users/donghwankim/git/asity/bridge-vertx2/src/main/java/io/cettia/asity/bridge/vertx2/AsityWebSocketHandler.java:30: error: semicolon missing
[ERROR]  * httpServer.websocketHandler(new AsityWebSocketHandler().onwebsocket(http -&gt {}));
[ERROR]                                                                              ^
[ERROR] 
[ERROR] Command line was: /Library/Java/JavaVirtualMachines/jdk1.8.0_112.jdk/Contents/Home/jre/../bin/javadoc @options @packages
[ERROR] 
[ERROR] Refer to the generated Javadoc files in '/Users/donghwankim/git/asity/target/site/apidocs' dir.
[ERROR] 
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Rewrite Play bridge in Scala

Because the current implementation uses Play's Java API, the following features are missing in Play bridge. In other means, they would be supported probably with Play's Scala API.

  • Play Java API requires to fix the data type to be used in the connection both in HTTP and WebSocket. It's not a problem in PlayServerHttpExchange, but in PlayServerWebSocket, text frame and binary frame can't be used together in a single connection.
  • Play doesn't support reading request asynchronously but I'm not sure Scala API can help it.
  • With Java API, a user have to use internal API which has been changed even in patch release. Scala API may solve that issue as well. (Maybe using Scala implementation and Java wrapper API just like Play framework itself)

New implementation should have unit tests and come with helper class making it easy to bridge application and Play. However, to make sure Java API's limit, we should contact their community first.

Review Actions interface

Actions is a powerful interface to define a specific event using Action and usually used internally by event firer. Typically, it backs up method like oneventname(Action<Event> action) internally and change in Actions doesn't affect event firer's API. Though, since it's very useful, it would be nice for user to use it for their own purpose. However, the following points should be considered to encourage doing that.

  • Interface name
    Actions is vague name and is named from jQuery's Callbacks object that was inspiring to write Actions interface. ActionStack, ActionPipeline or EventDefiner, and so on look better.
  • A way to configure option
    I'm not sure which way is better among setter, POJO option, option builder, and so on but clearly it's not needed to change such option in runtime as it defines a specific event.
  • Flow control
    Considering various events, flow of executing action should be able to be controlled by event firer or listener. Sometimes actions should be executed in a row asynchronously or synchronously and also sometimes firing should be stopped by some condition. (For example, a process to find proper cettia transport in client may be one of usages using this.) Many ways are available: 1. A special class extending ThreadLocal to acquire flow controller 2. A special action to control flow 3. A special method on Actions to control flow. We need to find more flow control cases and determine how to achieve that. Substituting event object in firing event may be required as well.
  • Benchmark Netty and Grizzly
    Both frameworks have similar component e.g. Pipeline and Filter. See what functionalities should be provided.

Play bridge's readAsText(String charset) doesn't work as expected

I found that testReadAsTextWithCharset fails with the following change:

Index: test/src/main/java/io/cettia/asity/test/ServerHttpExchangeTestBase.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- test/src/main/java/io/cettia/asity/test/ServerHttpExchangeTestBase.java	(date 1561814080000)
+++ test/src/main/java/io/cettia/asity/test/ServerHttpExchangeTestBase.java	(date 1561877782000)
@@ -167,11 +167,11 @@
         threadAssertEquals(body.toString(), "시간 속에 만들어진 무대 위에 그대는 없다");
         resume();
       })
-      .readAsText("utf-8");
+      .readAsText("euc-kr");
     });
     client.newRequest(uri()).method(HttpMethod.POST)
-    .content(new StringContentProvider("시간 속에 만들어진 무대 위에 그대는 없다", "utf-8"),
-      "text/plain; charset=euc-kr").send(ASYNC);
+    .content(new StringContentProvider("시간 속에 만들어진 무대 위에 그대는 없다", "euc-kr"),
+      "text/plain; charset=utf-8").send(ASYNC);
     await();
   }

Here's the log.

[ERROR] Tests run: 20, Failures: 1, Errors: 0, Skipped: 2, Time elapsed: 2.835 s <<< FAILURE! - in io.cettia.asity.bridge.play2.PlayServerHttpExchangeTest
[ERROR] testReadAsTextWithCharset(io.cettia.asity.bridge.play2.PlayServerHttpExchangeTest)  Time elapsed: 0.158 s  <<< FAILURE!
java.lang.AssertionError: expected:<???? ???? ???????? ???? ???? ?????? ????> but was:<?? ?? ???? ?? ?? ??? ??>

[INFO] 
[INFO] Results:
[INFO] 
[ERROR] Failures: 
[ERROR]   PlayServerHttpExchangeTest>ServerHttpExchangeTestBase.lambda$setUp$0:65->ServerHttpExchangeTestBase.lambda$testReadAsTextWithCharset$9:170->ServerHttpExchangeTestBase.lambda$null$8:167->ConcurrentTestCase.threadAssertEquals:33 expected:<???? ???? ???????? ???? ???? ?????? ????> but was:<?? ?? ???? ?? ?? ??? ??>

Other bridges have no such issue. Play doesn't seem to give raw bytes for some reason.

Improve logging

  • Log only if the log level is set to DEBUG
  • Log received data as well as sent data
  • Use simple name instead of FQCN

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.