Asity is a lightweight abstraction layer for various web frameworks on the Java Virtual Machine. It is designed to achieve and exploit "Write Once, Run Anywhere" by establishing an ecosystem of universally reusable web fragments* that run across different frameworks in the Java ecosystem. It provides abstractions for HTTP and WebSocket, and implementations per framework called bridges which are transparent to end-users and don't sacrifice the framework's performance, productivity and philosophy.
Web fragment authors can write a web fragment once and support almost all popular web frameworks in Java, and end-users can choose any technology stack they wish and use web fragments without being frustrated by compatibility issues.
* Web fragment represents a component that receives HTTP request-response or WebSocket connection like a controller in MVC but is able to be compatible with any web framework on the JVM.
At the code level, a web fragment is a set of Action
s to handle ServerHttpExchange
or ServerWebSocket
, which represents HTTP request-response exchange and WebSocket connection, respectively. These APIs are asynchronous and designed to conform the relevant RFC specifications, i.e. RFC2616 and RFC6455, from a pragmatic perspective.
Let's take a look at the APIs by building an echo fragment which simply respond to the client with whatever data the client sent. The data to exchange between server and client is a chunk of the Chunked transfer encoding in case of HTTP, and a text frame and a binary frame in case of WebSocket. Before getting started, be sure that you have Java 8+ and Maven 3+ installed.
Add a io.cettia.asity:asity-http:2.0.0
(Javadoc) as a dependency of your fragment.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-http</artifactId>
<version>2.0.0</version>
</dependency>
Then write an Action
consuming ServerHttpExchange
.
package io.cettia.asity.example.echo;
import io.cettia.asity.action.Action;
import io.cettia.asity.http.HttpStatus;
import io.cettia.asity.http.ServerHttpExchange;
import java.nio.ByteBuffer;
public class HttpEchoServer implements Action<ServerHttpExchange> {
@Override
public void on(ServerHttpExchange http) {
// Reads request URI, method and headers
System.out.println(http.method() + " " + http.uri());
http.headerNames().stream().forEach(name -> System.out.println(name + ": " + String.join(", ", http.headers(name))));
// Writes response status code and headers
http.setStatus(HttpStatus.OK).setHeader("content-type", http.header("content-type"));
// Reads a chunk from request body and writes it to response body
http.readAsBinary().onchunk((ByteBuffer binary) -> http.write(binary));
// If request body is supposed to be text,
// http.readAsText().onchunk((String chunk) -> http.write(chunk));
// Ends response if request ends
http.onend((Void v) -> http.end());
// Exception handling
http.onerror((Throwable t) -> t.printStackTrace()).onclose((Void v) -> System.out.println("disconnected"));
}
}
Add a io.cettia.asity:asity-websocket:2.0.0
(Javadoc) as a dependency of your fragment.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-websocket</artifactId>
<version>2.0.0</version>
</dependency>
Then write an Action
consuming ServerWebSocket
.
package io.cettia.asity.example.echo;
import io.cettia.asity.action.Action;
import io.cettia.asity.websocket.ServerWebSocket;
import java.nio.ByteBuffer;
public class WebSocketEchoServer implements Action<ServerWebSocket> {
@Override
public void on(ServerWebSocket ws) {
// Reads handshake request URI and headers
System.out.println(ws.uri());
ws.headerNames().stream().forEach(name -> System.out.println(name + ": " + String.join(", ", ws.headers(name))));
// Sends the received text frame and binary frame back
ws.ontext((String text) -> ws.send(text)).onbinary((ByteBuffer binary) -> ws.send(binary));
// Exception handling
ws.onerror((Throwable t) -> t.printStackTrace());
}
}
To run a web fragment on your framework, you need to plug the fragment in to the framework through a dedicated bridge for the framework. A bridge is a minimal implementation; just enough to convert a framework's HTTP request-response exchange and WebSocket connection to the Asity's ServerHttpExchange
and ServerWebSocket
, and feed web fragments with them. Note that even if your favorite framework is not supported, with about 200 lines of code, you can write a bridge to your framework.
Let's map the echo fragment above to the path /echo
.
Add a io.cettia.asity:asity-bridge-jwa1:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-jwa1</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityServerEndpoint
as a WebSocket server endpoint in a server container. When registering the server endpoint, you should put a handshake request instance into a map returned by ServerEndpointConfig#getUserProperties
with the javax.websocket.server.HandshakeRequest
key by overriding a Configurator#modifyHandshake
method.
package io.cettia.asity.example.jwa1;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.jwa1.AsityServerEndpoint;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.websocket.ServerWebSocket;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.websocket.DeploymentException;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpointConfig;
@WebListener
public class EchoServerInitializer implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
// Web fragments
Action<ServerWebSocket> wsAction = new WebSocketEchoServer();
ServletContext context = event.getServletContext();
ServerContainer container = (ServerContainer) context.getAttribute(ServerContainer.class.getName());
ServerEndpointConfig.Configurator configurator = new ServerEndpointConfig.Configurator() {
@Override
public <T> T getEndpointInstance(Class<T> endpointClass) {
AsityServerEndpoint asityServerEndpoint = new AsityServerEndpoint().onwebsocket(wsAction);
return endpointClass.cast(asityServerEndpoint);
}
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
config.getUserProperties().put(HandshakeRequest.class.getName(), request);
}
};
try {
container.addEndpoint(ServerEndpointConfig.Builder.create(AsityServerEndpoint.class, "/echo").configurator(configurator).build());
} catch (DeploymentException e) {
throw new RuntimeException(e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
}
Now you can handle WebSocket connections from /echo
asynchronously through a AsityServerEndpoint
's onwebsocket
method.
A full example is available at https://github.com/cettia/asity/tree/master/example-jwa1.
Add io.cettia.asity:asity-bridge-servlet3:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-servlet3</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityServlet
as a servlet in a servlet context. When registering the servlet, you should set asyncSupported
to true
.
package io.cettia.asity.example.servlet3;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.servlet3.AsityServlet;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;
@WebListener
public class EchoServerInitializer implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
// Web fragments
Action<ServerHttpExchange> httpAction = new HttpEchoServer();
ServletContext context = event.getServletContext();
Servlet servlet = new AsityServlet().onhttp(httpAction);
ServletRegistration.Dynamic reg = context.addServlet(AsityServlet.class.getName(), servlet);
reg.setAsyncSupported(true);
reg.addMapping("/echo");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
}
Now you can handle HTTP requests from /echo
asynchronously through a AsityServlet
's onhttp
method.
Note
ServerHttpExchange
's onclose
isn't supported.A full example is available at https://github.com/cettia/asity/tree/master/example-servlet3.
Add a io.cettia.asity:asity-bridge-spring-webflux5:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-spring-webflux5</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityHandlerFunction
as a handler function and a AsityWebSocketHandler
as a WebSocket handler.
package io.cettia.asity.example.spring.webflux5;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.spring.webflux5.AsityHandlerFunction;
import io.cettia.asity.bridge.spring.webflux5.AsityWebSocketHandler;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.springframework.web.reactive.function.server.RequestPredicates.headers;
import static org.springframework.web.reactive.function.server.RequestPredicates.path;
@SpringBootApplication
@EnableWebFlux
public class EchoServer {
@Bean
public Action<ServerHttpExchange> httpAction() {
return new HttpEchoServer();
}
@Bean
public Action<ServerWebSocket> wsAction() {
return new WebSocketEchoServer();
}
@Bean
public RouterFunction<ServerResponse> httpMapping() {
AsityHandlerFunction asityHandlerFunction = new AsityHandlerFunction().onhttp(httpAction());
return RouterFunctions.route(
path("/echo")
// Excludes WebSocket handshake requests
.and(headers(headers -> !"websocket".equalsIgnoreCase(headers.asHttpHeaders().getUpgrade()))), asityHandlerFunction);
}
@Bean
public HandlerMapping wsMapping() {
AsityWebSocketHandler asityWebSocketHandler = new AsityWebSocketHandler().onwebsocket(wsAction());
Map<String, WebSocketHandler> map = new LinkedHashMap<>();
map.put("/echo", asityWebSocketHandler);
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setUrlMap(map);
return mapping;
}
@Bean
public WebSocketHandlerAdapter webSocketHandlerAdapter() {
return new WebSocketHandlerAdapter();
}
public static void main(String[] args) {
SpringApplication.run(EchoServer.class, args);
}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityHandlerFunction
's onhttp
method and a AsityWebSocketHandler
's onwebsocket
method.
Note
ServerHttpExchange
's onclose
isn't supported.A full example is available at https://github.com/cettia/asity/tree/master/example-spring-webflux5.
Add a io.cettia.asity:asity-bridge-spring-webmvc4:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-spring-webmvc4</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityController
as a controller bean and a AsityWebSocketHandler
as a WebSocket handler bean.
package io.cettia.asity.example.spring.webmvc4;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.spring.webmvc4.AsityController;
import io.cettia.asity.bridge.spring.webmvc4.AsityWebSocketHandler;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import javax.servlet.http.HttpServletRequest;
@SpringBootApplication
@EnableWebMvc
@EnableWebSocket
public class EchoServer implements WebSocketConfigurer {
@Bean
public Action<ServerHttpExchange> httpAction() {
return new HttpEchoServer();
}
@Bean
public Action<ServerWebSocket> wsAction() {
return new WebSocketEchoServer();
}
@Bean
public HandlerMapping httpMapping() {
AsityController asityController = new AsityController().onhttp(httpAction());
AbstractHandlerMapping mapping = new AbstractHandlerMapping() {
@Override
protected Object getHandlerInternal(HttpServletRequest request) {
// Check whether a path equals '/echo'
return "/echo".equals(request.getRequestURI()) &&
// Delegates WebSocket handshake requests to a webSocketHandler bean
!"websocket".equalsIgnoreCase(request.getHeader("upgrade")) ? asityController : null;
}
};
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
return mapping;
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
AsityWebSocketHandler asityWebSocketHandler = new AsityWebSocketHandler().onwebsocket(wsAction());
registry.addHandler(asityWebSocketHandler, "/echo");
}
public static void main(String[] args) {
SpringApplication.run(EchoServer.class);
}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityController
's onhttp
method and a AsityWebSocketHandler
's onwebsocket
method.
Note
ServerHttpExchange
's onclose
isn't supported.A full example is available at https://github.com/cettia/asity/tree/master/example-spring-webmvc4.
Add a io.cettia.asity:asity-bridge-vertx3:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-vertx3</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityRequestHandler
as a HTTP request handler and a AsityWebSocketHandler
as a WebSocket connection handler in a http server.
package io.cettia.asity.example.vertx3;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.vertx3.AsityRequestHandler;
import io.cettia.asity.bridge.vertx3.AsityWebSocketHandler;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServer;
public class EchoServerVerticle extends AbstractVerticle {
@Override
public void start() {
// Web fragments
Action<ServerHttpExchange> httpAction = new HttpEchoServer();
Action<ServerWebSocket> wsAction = new WebSocketEchoServer();
HttpServer httpServer = vertx.createHttpServer();
AsityRequestHandler asityRequestHandler = new AsityRequestHandler().onhttp(httpAction);
httpServer.requestHandler(request -> {
if (request.path().equals("/echo")) {
asityRequestHandler.handle(request);
}
});
AsityWebSocketHandler asityWebsocketHandler = new AsityWebSocketHandler().onwebsocket(wsAction);
httpServer.websocketHandler(socket -> {
if (socket.path().equals("/echo")) {
asityWebsocketHandler.handle(socket);
}
});
httpServer.listen(8080);
}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityRequestHandler
's onhttp
method and a AsityWebSocketHandler
's onwebsocket
method.
A full example is available at https://github.com/cettia/asity/tree/master/example-vertx3.
Add a io.cettia.asity:asity-bridge-netty4:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-netty4</artifactId>
<version>2.0.0</version>
</dependency>
Then add a AsityServerCodec
as a channel handler to a channel pipeline. When configuring the handler, you should add HttpServerCodec
in front of the handler.
package io.cettia.asity.example.netty4;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.netty4.AsityServerCodec;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpServerCodec;
import java.net.URI;
public class EchoServer {
public static void main(String[] args) throws Exception {
// Web fragments
Action<ServerHttpExchange> httpAction = new HttpEchoServer();
Action<ServerWebSocket> wsAction = new WebSocketEchoServer();
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
AsityServerCodec asityServerCodec = new AsityServerCodec() {
@Override
protected boolean accept(HttpRequest req) {
return URI.create(req.uri()).getPath().equals("/echo");
}
};
asityServerCodec.onhttp(httpAction).onwebsocket(wsAction);
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpServerCodec()).addLast(asityServerCodec);
}
});
Channel channel = bootstrap.bind(8080).sync().channel();
channel.closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityServerCodec
's onhttp
and onwebsocket
methods.
A full example is available at https://github.com/cettia/asity/tree/master/example-netty4.
Add a io.cettia.asity:asity-bridge-grizzly2:2.0.0
(Javadoc)as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-grizzly2</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityHttpHandler
as a HTTP request handler in a server configuration and a AsityWebSocketApplication
as a WebSocket application in a WebSocket engine.
package io.cettia.asity.example.grizzly2;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.grizzly2.AsityHttpHandler;
import io.cettia.asity.bridge.grizzly2.AsityWebSocketApplication;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import org.glassfish.grizzly.http.server.ServerConfiguration;
import org.glassfish.grizzly.websockets.WebSocketAddOn;
import org.glassfish.grizzly.websockets.WebSocketEngine;
public class EchoServer {
public static void main(String[] args) throws Exception {
// Web fragments
Action<ServerHttpExchange> httpAction = new HttpEchoServer();
Action<ServerWebSocket> wsAction = new WebSocketEchoServer();
HttpServer httpServer = HttpServer.createSimpleServer();
ServerConfiguration config = httpServer.getServerConfiguration();
config.addHttpHandler(new AsityHttpHandler().onhttp(httpAction), "/echo");
NetworkListener listener = httpServer.getListener("grizzly");
listener.registerAddOn(new WebSocketAddOn());
WebSocketEngine.getEngine().register("", "/echo", new AsityWebSocketApplication().onwebsocket(wsAction));
httpServer.start();
System.in.read();
}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityHttpHandler
's onhttp
method and a AsityWebSocketApplication
's onwebsocket
method.
Note
javax.servlet:javax.servlet-api:4.y.z
.A full example is available at https://github.com/cettia/asity/tree/master/example-grizzly2.
Add a io.cettia.asity:asity-bridge-vertx2:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-vertx2</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityRequestHandler
as a HTTP request handler and a AsityWebSocketHandler
as a WebSocket connection handler in a http server.
package io.cettia.asity.example.vertx2;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.vertx2.AsityRequestHandler;
import io.cettia.asity.bridge.vertx2.AsityWebSocketHandler;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import org.vertx.java.core.http.HttpServer;
import org.vertx.java.core.http.RouteMatcher;
import org.vertx.java.platform.Verticle;
public class EchoServerVerticle extends Verticle {
@Override
public void start() {
// Web fragments
Action<ServerHttpExchange> httpAction = new HttpEchoServer();
Action<ServerWebSocket> wsAction = new WebSocketEchoServer();
HttpServer httpServer = vertx.createHttpServer();
RouteMatcher httpMatcher = new RouteMatcher();
httpMatcher.all("/echo", new AsityRequestHandler().onhttp(httpAction));
httpServer.requestHandler(httpMatcher);
AsityWebSocketHandler websocketHandler = new AsityWebSocketHandler().onwebsocket(wsAction);
httpServer.websocketHandler(socket -> {
if (socket.path().equals("/echo")) {
websocketHandler.handle(socket);
}
});
httpServer.listen(8080);
}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityRequestHandler
's onhttp
method and a AsityWebSocketHandler
's onwebsocket
method.
A full example is available at https://github.com/cettia/asity/tree/master/example-vertx2.
Add a io.cettia.asity:asity-bridge-atmosphere2:2.0.0
(Javadoc) as a dependency of your application.
<dependency>
<groupId>io.cettia.asity</groupId>
<artifactId>asity-bridge-atmosphere2</artifactId>
<version>2.0.0</version>
</dependency>
Then register a AsityAtmosphereServlet
as a servlet in a servlet context. When registering the servlet, you should set asyncSupported
to true
and an init parameter org.atmosphere.cpr.AtmosphereInterceptor.disableDefaults
to true
.
package io.cettia.asity.example.atmosphere2;
import io.cettia.asity.action.Action;
import io.cettia.asity.bridge.atmosphere2.AsityAtmosphereServlet;
import io.cettia.asity.example.echo.HttpEchoServer;
import io.cettia.asity.example.echo.WebSocketEchoServer;
import io.cettia.asity.http.ServerHttpExchange;
import io.cettia.asity.websocket.ServerWebSocket;
import org.atmosphere.cpr.ApplicationConfig;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;
@WebListener
public class EchoServerInitializer implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
// Web fragments
Action<ServerHttpExchange> httpAction = new HttpEchoServer();
Action<ServerWebSocket> wsAction = new WebSocketEchoServer();
ServletContext context = event.getServletContext();
Servlet servlet = new AsityAtmosphereServlet().onhttp(httpAction).onwebsocket(wsAction);
ServletRegistration.Dynamic reg = context.addServlet(AsityAtmosphereServlet.class.getName(), servlet);
reg.setAsyncSupported(true);
reg.setInitParameter(ApplicationConfig.DISABLE_ATMOSPHEREINTERCEPTOR, Boolean.TRUE.toString());
reg.addMapping("/echo");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
}
Now you can handle HTTP requests and WebSocket connections from /echo
asynchronously through a AsityAtmosphereServlet
's onhttp
and onwebsocket
methods.
Note
ServerHttpExchange
's onclose
isn't supported.ServerWebSocket
's headers
doesn't support a header with multiple values.A full example is available at https://github.com/cettia/asity/tree/master/example-atmosphere2.
A web fragment is not just limited to echo. Check out an interview with the creator of Asity to learn more about use cases for Asity. You can build a framework built on top of HTTP and WebSocket, a server-side Java implementation, a middleware layer for Java, etc. The followings are some of the projects to demonstrate the real world use case of Asity.
Asity is an open source project licensed under Apache License 2.0 and driven by the community, for the community. If you are interested and would like to be more involved, feel free to join the community and share your feedback.