[BAEL-8499] - Moved server related codes / articles to libraries-server module
This commit is contained in:
7
libraries-server/README.md
Normal file
7
libraries-server/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### Relevant articles
|
||||
|
||||
- [Embedded Jetty Server in Java](http://www.baeldung.com/jetty-embedded)
|
||||
- [Introduction to Netty](http://www.baeldung.com/netty)
|
||||
- [Exceptions in Netty](http://www.baeldung.com/netty-exception-handling)
|
||||
- [Programatically Create, Configure, and Run a Tomcat Server](http://www.baeldung.com/tomcat-programmatic-setup)
|
||||
- [Creating and Configuring Jetty 9 Server in Java](http://www.baeldung.com/jetty-java-programmatic)
|
||||
@@ -14,6 +14,73 @@
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.2.0</version>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.assertj/assertj-core -->
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>${assertj.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>${commons.io.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>${netty.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- tomcat -->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat</groupId>
|
||||
<artifactId>tomcat-catalina</artifactId>
|
||||
<version>${tomcat.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
<properties>
|
||||
<assertj.version>3.6.2</assertj.version>
|
||||
<httpclient.version>4.5.3</httpclient.version>
|
||||
<commons.io.version>2.5</commons.io.version>
|
||||
<jetty.version>9.4.8.v20171121</jetty.version>
|
||||
<netty.version>4.1.20.Final</netty.version>
|
||||
<commons.collections.version>4.1</commons.collections.version>
|
||||
<junit.version>4.12</junit.version>
|
||||
<tomcat.version>8.5.24</tomcat.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class AsyncServlet extends HttpServlet {
|
||||
private static final String HEAVY_RESOURCE = "This is some heavy resource that will be served in an async way";
|
||||
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
ByteBuffer content = ByteBuffer.wrap(HEAVY_RESOURCE.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
AsyncContext async = request.startAsync();
|
||||
ServletOutputStream out = response.getOutputStream();
|
||||
out.setWriteListener(new WriteListener() {
|
||||
@Override
|
||||
public void onWritePossible() throws IOException {
|
||||
while (out.isReady()) {
|
||||
if (!content.hasRemaining()) {
|
||||
response.setStatus(200);
|
||||
async.complete();
|
||||
return;
|
||||
}
|
||||
out.write(content.get());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
getServletContext().log("Async Error", t);
|
||||
async.complete();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BlockingServlet extends HttpServlet {
|
||||
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
response.setContentType("application/json");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().println("{ \"status\": \"ok\"}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
|
||||
class JettyServer {
|
||||
|
||||
private Server server;
|
||||
|
||||
void start() throws Exception {
|
||||
|
||||
int maxThreads = 100;
|
||||
int minThreads = 10;
|
||||
int idleTimeout = 120;
|
||||
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, minThreads, idleTimeout);
|
||||
|
||||
server = new Server(threadPool);
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(8090);
|
||||
server.setConnectors(new Connector[] { connector });
|
||||
|
||||
ServletHandler servletHandler = new ServletHandler();
|
||||
server.setHandler(servletHandler);
|
||||
|
||||
servletHandler.addServletWithMapping(BlockingServlet.class, "/status");
|
||||
servletHandler.addServletWithMapping(AsyncServlet.class, "/heavy/async");
|
||||
|
||||
server.start();
|
||||
|
||||
}
|
||||
|
||||
void stop() throws Exception {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* Simple factory for creating Jetty basic instances.
|
||||
*
|
||||
* @author Donato Rimenti
|
||||
*
|
||||
*/
|
||||
public class JettyServerFactory {
|
||||
|
||||
/**
|
||||
* Exposed context of the app.
|
||||
*/
|
||||
public final static String APP_PATH = "/myApp";
|
||||
|
||||
/**
|
||||
* The server port.
|
||||
*/
|
||||
public final static int SERVER_PORT = 13133;
|
||||
|
||||
/**
|
||||
* Private constructor to avoid instantiation.
|
||||
*/
|
||||
private JettyServerFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a simple server listening on port 80 with a timeout of 30 seconds
|
||||
* for connections and no handlers.
|
||||
*
|
||||
* @return a server
|
||||
*/
|
||||
public static Server createBaseServer() {
|
||||
Server server = new Server();
|
||||
|
||||
// Adds a connector for port 80 with a timeout of 30 seconds.
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setPort(SERVER_PORT);
|
||||
connector.setHost("127.0.0.1");
|
||||
connector.setIdleTimeout(30000);
|
||||
server.addConnector(connector);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server which delegates the request handling to a web
|
||||
* application.
|
||||
*
|
||||
* @return a server
|
||||
*/
|
||||
public static Server createWebAppServer() {
|
||||
// Adds an handler to a server and returns it.
|
||||
Server server = createBaseServer();
|
||||
String webAppFolderPath = JettyServerFactory.class.getClassLoader().getResource("jetty-embedded-demo-app.war").getPath();
|
||||
Handler webAppHandler = new WebAppContext(webAppFolderPath, APP_PATH);
|
||||
server.setHandler(webAppHandler);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a server which delegates the request handling to both a logging
|
||||
* handler and to a web application, in this order.
|
||||
*
|
||||
* @return a server
|
||||
*/
|
||||
public static Server createMultiHandlerServer() {
|
||||
Server server = createBaseServer();
|
||||
|
||||
// Creates the handlers and adds them to the server.
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
|
||||
String webAppFolderPath = JettyServerFactory.class.getClassLoader().getResource("jetty-embedded-demo-app.war").getPath();
|
||||
Handler customRequestHandler = new WebAppContext(webAppFolderPath, APP_PATH);
|
||||
handlers.addHandler(customRequestHandler);
|
||||
|
||||
Handler loggingRequestHandler = new LoggingRequestHandler();
|
||||
handlers.addHandler(loggingRequestHandler);
|
||||
|
||||
server.setHandler(handlers);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Handler implementation which simply logs that a request has been received.
|
||||
*
|
||||
* @author Donato Rimenti
|
||||
*/
|
||||
public class LoggingRequestHandler implements Handler {
|
||||
|
||||
/**
|
||||
* Logger.
|
||||
*/
|
||||
private final static Logger LOG = LoggerFactory.getLogger(LoggingRequestHandler.class);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#addLifeCycleListener(org.
|
||||
* eclipse.jetty.util.component.LifeCycle.Listener)
|
||||
*/
|
||||
@Override
|
||||
public void addLifeCycleListener(Listener arg0) {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isFailed()
|
||||
*/
|
||||
@Override
|
||||
public boolean isFailed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isRunning()
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStarted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStarting()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStarting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStopped()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStopped() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#isStopping()
|
||||
*/
|
||||
@Override
|
||||
public boolean isStopping() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.jetty.util.component.LifeCycle#removeLifeCycleListener(org.
|
||||
* eclipse.jetty.util.component.LifeCycle.Listener)
|
||||
*/
|
||||
@Override
|
||||
public void removeLifeCycleListener(Listener arg0) {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.util.component.LifeCycle#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#destroy()
|
||||
*/
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#getServer()
|
||||
*/
|
||||
@Override
|
||||
public Server getServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#handle(java.lang.String,
|
||||
* org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
|
||||
* javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public void handle(String arg0, Request arg1, HttpServletRequest arg2, HttpServletResponse arg3) throws IOException, ServletException {
|
||||
LOG.info("Received a new request");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.server.Handler#setServer(org.eclipse.jetty.server.
|
||||
* Server)
|
||||
*/
|
||||
@Override
|
||||
public void setServer(Server server) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
public class CalculatorOperationHandler extends SimpleChannelInboundHandler<Operation> {
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext ctx, Operation msg) throws Exception {
|
||||
Long result = calculateEndpoint(msg);
|
||||
sendHttpResponse(ctx, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CREATED), result.toString());
|
||||
ctx.fireChannelRead(result);
|
||||
}
|
||||
|
||||
private long calculateEndpoint(Operation operation) {
|
||||
|
||||
String operator = operation.getOperator().toLowerCase().trim();
|
||||
switch (operator) {
|
||||
case "add":
|
||||
return operation.getNumber1() + operation.getNumber2();
|
||||
case "multiply":
|
||||
return operation.getNumber1() * operation.getNumber2();
|
||||
default:
|
||||
throw new IllegalArgumentException("Operation not defined");
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpResponse res, String content) {
|
||||
|
||||
// Generate an error page if response getStatus code is not OK (200).
|
||||
ByteBuf buf = Unpooled.copiedBuffer(content, CharsetUtil.UTF_8);
|
||||
res.content().writeBytes(buf);
|
||||
|
||||
HttpUtil.setContentLength(res, res.content().readableBytes());
|
||||
|
||||
ctx.channel().writeAndFlush(res);
|
||||
}
|
||||
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
|
||||
throws Exception {
|
||||
|
||||
sendHttpResponse(ctx, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR), "Operation not defined");
|
||||
ctx.fireExceptionCaught(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ChannelHandlerA extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private Logger logger = Logger.getLogger(getClass().getName());
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
throw new Exception("Ooops");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
logger.info("Exception Occurred in ChannelHandler A");
|
||||
ctx.fireExceptionCaught(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ChannelHandlerB extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private Logger logger = Logger.getLogger(getClass().getName());
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
logger.info("Exception Handled in ChannelHandler B");
|
||||
logger.info(cause.getLocalizedMessage());
|
||||
// do more exception handling
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
public class ClientHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
RequestData msg = new RequestData();
|
||||
msg.setIntValue(123);
|
||||
msg.setStringValue("all work and no play makes jack a dull boy");
|
||||
ctx.writeAndFlush(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
System.out.println(msg);
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
|
||||
public class HttpMessageHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
|
||||
|
||||
String uri = msg.uri();
|
||||
HttpMethod httpMethod = msg.method();
|
||||
HttpHeaders headers = msg.headers();
|
||||
|
||||
if (HttpMethod.GET == httpMethod) {
|
||||
|
||||
String[] uriComponents = uri.split("[?]");
|
||||
String endpoint = uriComponents[0];
|
||||
String[] queryParams = uriComponents[1].split("&");
|
||||
|
||||
if ("/calculate".equalsIgnoreCase(endpoint)) {
|
||||
|
||||
String[] firstQueryParam = queryParams[0].split("=");
|
||||
String[] secondQueryParam = queryParams[1].split("=");
|
||||
|
||||
Integer a = Integer.valueOf(firstQueryParam[1]);
|
||||
Integer b = Integer.valueOf(secondQueryParam[1]);
|
||||
String operator = headers.get("operator");
|
||||
|
||||
Operation operation = new Operation(a, b, operator);
|
||||
ctx.fireChannelRead(operation);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("HTTP method not supported");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
public class NettyClient {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String host = "localhost";
|
||||
int port = 8080;
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
try {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.group(workerGroup);
|
||||
b.channel(NioSocketChannel.class);
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
b.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(), new ClientHandler());
|
||||
}
|
||||
});
|
||||
|
||||
ChannelFuture f = b.connect(host, port).sync();
|
||||
|
||||
f.channel().closeFuture().sync();
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
public class NettyServer {
|
||||
|
||||
private int port;
|
||||
|
||||
private NettyServer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int port;
|
||||
if (args.length > 0) {
|
||||
port = Integer.parseInt(args[0]);
|
||||
} else {
|
||||
port = 8080;
|
||||
}
|
||||
new NettyServer(port).run();
|
||||
}
|
||||
|
||||
private void run() throws Exception {
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new RequestDecoder(), new ResponseDataEncoder(), new ProcessingHandler());
|
||||
}
|
||||
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
ChannelFuture f = b.bind(port).sync();
|
||||
f.channel().closeFuture().sync();
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
bossGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
public class NettyServerB {
|
||||
|
||||
private int port;
|
||||
|
||||
private NettyServerB(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
private void run() throws Exception {
|
||||
|
||||
EventLoopGroup bossGroup = new NioEventLoopGroup();
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast(new ChannelHandlerA(), new ChannelHandlerB());
|
||||
}
|
||||
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
ChannelFuture f = b.bind(port).sync(); // (7)
|
||||
f.channel().closeFuture().sync();
|
||||
} finally {
|
||||
workerGroup.shutdownGracefully();
|
||||
bossGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new NettyServerB(8080).run();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Operation implements Serializable {
|
||||
|
||||
private Integer number1;
|
||||
private Integer number2;
|
||||
private String operator;
|
||||
|
||||
public Operation(Integer number1, Integer number2, String operator) {
|
||||
this.number1 = number1;
|
||||
this.number2 = number2;
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public Integer getNumber1() {
|
||||
return number1;
|
||||
}
|
||||
|
||||
public void setNumber1(Integer number1) {
|
||||
this.number1 = number1;
|
||||
}
|
||||
|
||||
public Integer getNumber2() {
|
||||
return number2;
|
||||
}
|
||||
|
||||
public void setNumber2(Integer number2) {
|
||||
this.number2 = number2;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Operation{" +
|
||||
"number1=" + number1 +
|
||||
", number2=" + number2 +
|
||||
", operator='" + operator + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
public class ProcessingHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
RequestData requestData = (RequestData) msg;
|
||||
ResponseData responseData = new ResponseData();
|
||||
responseData.setIntValue(requestData.getIntValue() * 2);
|
||||
ChannelFuture future = ctx.writeAndFlush(responseData);
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
System.out.println(requestData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
public class RequestData {
|
||||
private int intValue;
|
||||
private String stringValue;
|
||||
|
||||
int getIntValue() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
void setIntValue(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
|
||||
String getStringValue() {
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
void setStringValue(String stringValue) {
|
||||
this.stringValue = stringValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RequestData{" + "intValue=" + intValue + ", stringValue='" + stringValue + '\'' + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class RequestDataEncoder extends MessageToByteEncoder<RequestData> {
|
||||
|
||||
private final Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, RequestData msg, ByteBuf out) throws Exception {
|
||||
out.writeInt(msg.getIntValue());
|
||||
out.writeInt(msg.getStringValue().length());
|
||||
out.writeCharSequence(msg.getStringValue(), charset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
|
||||
public class RequestDecoder extends ReplayingDecoder<RequestData> {
|
||||
|
||||
private final Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
RequestData data = new RequestData();
|
||||
data.setIntValue(in.readInt());
|
||||
int strLen = in.readInt();
|
||||
data.setStringValue(in.readCharSequence(strLen, charset).toString());
|
||||
out.add(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
public class ResponseData {
|
||||
private int intValue;
|
||||
|
||||
int getIntValue() {
|
||||
return intValue;
|
||||
}
|
||||
|
||||
void setIntValue(int intValue) {
|
||||
this.intValue = intValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResponseData{" + "intValue=" + intValue + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ReplayingDecoder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ResponseDataDecoder extends ReplayingDecoder<ResponseData> {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
ResponseData data = new ResponseData();
|
||||
data.setIntValue(in.readInt());
|
||||
out.add(data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
public class ResponseDataEncoder extends MessageToByteEncoder<ResponseData> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ResponseData msg, ByteBuf out) throws Exception {
|
||||
out.writeInt(msg.getIntValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
public class SimpleProcessingHandler extends ChannelInboundHandlerAdapter {
|
||||
private ByteBuf tmp;
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) {
|
||||
System.out.println("Handler added");
|
||||
tmp = ctx.alloc().buffer(4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
System.out.println("Handler removed");
|
||||
tmp.release();
|
||||
tmp = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
ByteBuf m = (ByteBuf) msg;
|
||||
tmp.writeBytes(m);
|
||||
m.release();
|
||||
if (tmp.readableBytes() >= 4) {
|
||||
RequestData requestData = new RequestData();
|
||||
requestData.setIntValue(tmp.readInt());
|
||||
ResponseData responseData = new ResponseData();
|
||||
responseData.setIntValue(requestData.getIntValue() * 2);
|
||||
ChannelFuture future = ctx.writeAndFlush(responseData);
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.baeldung.tomcat;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.annotation.WebFilter;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by adi on 1/14/18.
|
||||
*/
|
||||
@WebFilter(urlPatterns = "/my-servlet/*")
|
||||
public class MyFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
System.out.println("Filtering stuff...");
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
httpResponse.addHeader("myHeader", "myHeaderValue");
|
||||
chain.doFilter(request, httpResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.tomcat;
|
||||
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by adi on 1/10/18.
|
||||
*/
|
||||
@WebServlet(name = "com.baeldung.tomcat.programmatic.MyServlet", urlPatterns = { "/my-servlet" })
|
||||
public class MyServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
resp.getWriter().write("test");
|
||||
resp.getWriter().flush();
|
||||
resp.getWriter().close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.baeldung.tomcat;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.tomcat.util.descriptor.web.FilterDef;
|
||||
import org.apache.tomcat.util.descriptor.web.FilterMap;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by adi on 1/10/18.
|
||||
*/
|
||||
public class ProgrammaticTomcat {
|
||||
|
||||
private Tomcat tomcat = null;
|
||||
|
||||
// uncomment for live test
|
||||
// public static void main(String[] args) throws LifecycleException, ServletException, URISyntaxException, IOException {
|
||||
// startTomcat();
|
||||
// }
|
||||
|
||||
public void startTomcat() throws LifecycleException {
|
||||
tomcat = new Tomcat();
|
||||
tomcat.setPort(8080);
|
||||
tomcat.setHostname("localhost");
|
||||
String appBase = ".";
|
||||
tomcat.getHost().setAppBase(appBase);
|
||||
|
||||
File docBase = new File(System.getProperty("java.io.tmpdir"));
|
||||
Context context = tomcat.addContext("", docBase.getAbsolutePath());
|
||||
|
||||
// add a servlet
|
||||
Class servletClass = MyServlet.class;
|
||||
Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName());
|
||||
context.addServletMappingDecoded("/my-servlet/*", servletClass.getSimpleName());
|
||||
|
||||
// add a filter and filterMapping
|
||||
Class filterClass = MyFilter.class;
|
||||
FilterDef myFilterDef = new FilterDef();
|
||||
myFilterDef.setFilterClass(filterClass.getName());
|
||||
myFilterDef.setFilterName(filterClass.getSimpleName());
|
||||
context.addFilterDef(myFilterDef);
|
||||
|
||||
FilterMap myFilterMap = new FilterMap();
|
||||
myFilterMap.setFilterName(filterClass.getSimpleName());
|
||||
myFilterMap.addURLPattern("/my-servlet/*");
|
||||
context.addFilterMap(myFilterMap);
|
||||
|
||||
tomcat.start();
|
||||
// uncomment for live test
|
||||
// tomcat
|
||||
// .getServer()
|
||||
// .await();
|
||||
}
|
||||
|
||||
public void stopTomcat() throws LifecycleException {
|
||||
tomcat.stop();
|
||||
tomcat.destroy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
|
||||
|
||||
public class JettyIntegrationTest {
|
||||
private static JettyServer jettyServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws Exception {
|
||||
jettyServer = new JettyServer();
|
||||
jettyServer.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() throws Exception {
|
||||
jettyServer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenServer_whenSendRequestToBlockingServlet_thenReturnStatusOK() throws Exception {
|
||||
// given
|
||||
String url = "http://localhost:8090/status";
|
||||
HttpClient client = HttpClientBuilder.create().build();
|
||||
HttpGet request = new HttpGet(url);
|
||||
HttpResponse response = client.execute(request);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenServer_whenSendRequestToNonBlockingServlet_thenReturnStatusOK() throws Exception {
|
||||
// when
|
||||
String url = "http://localhost:8090/heavy/async";
|
||||
HttpClient client = HttpClientBuilder.create().build();
|
||||
HttpGet request = new HttpGet(url);
|
||||
HttpResponse response = client.execute(request);
|
||||
|
||||
// then
|
||||
assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200);
|
||||
String responseContent = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
assertThat(responseContent).isEqualTo("This is some heavy resource that will be served in an async way");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.baeldung.jetty;
|
||||
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test for {@link JettyServerFactory}.
|
||||
*
|
||||
* @author Donato Rimenti
|
||||
*
|
||||
*/
|
||||
public class JettyServerFactoryUnitTest {
|
||||
|
||||
/**
|
||||
* Tests that when a base server is provided a request returns a status 404.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void givenBaseServer_whenHttpRequest_thenStatus404() throws Exception {
|
||||
Server server = JettyServerFactory.createBaseServer();
|
||||
server.start();
|
||||
|
||||
int statusCode = sendGetRequest();
|
||||
|
||||
Assert.assertEquals(404, statusCode);
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when a web app server is provided a request returns a status
|
||||
* 200.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void givenWebAppServer_whenHttpRequest_thenStatus200() throws Exception {
|
||||
Server server = JettyServerFactory.createWebAppServer();
|
||||
server.start();
|
||||
|
||||
int statusCode = sendGetRequest();
|
||||
|
||||
Assert.assertEquals(200, statusCode);
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when a multi handler server is provided a request returns a
|
||||
* status 200.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void givenMultiHandlerServerServer_whenHttpRequest_thenStatus200() throws Exception {
|
||||
Server server = JettyServerFactory.createMultiHandlerServer();
|
||||
server.start();
|
||||
|
||||
int statusCode = sendGetRequest();
|
||||
|
||||
Assert.assertEquals(200, statusCode);
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a default HTTP GET request to the server and returns the response
|
||||
* status code.
|
||||
*
|
||||
* @return the status code of the response
|
||||
* @throws Exception
|
||||
*/
|
||||
private int sendGetRequest() throws Exception {
|
||||
HttpHost target = new HttpHost("localhost", JettyServerFactory.SERVER_PORT);
|
||||
HttpRequest request = new HttpGet(JettyServerFactory.APP_PATH);
|
||||
HttpClient client = HttpClientBuilder.create().build();
|
||||
HttpResponse response = client.execute(target, request);
|
||||
return response.getStatusLine().getStatusCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.baeldung.netty;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
|
||||
public class EmbeddedChannelUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenTwoChannelHandlers_testPipeline() {
|
||||
|
||||
final FullHttpRequest httpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
"/calculate?a=10&b=5");
|
||||
httpRequest.headers().add("Operator", "Add");
|
||||
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new HttpMessageHandler(), new CalculatorOperationHandler());
|
||||
|
||||
channel.pipeline().addFirst(new HttpMessageHandler()).addLast(new CalculatorOperationHandler());
|
||||
|
||||
// send HTTP request to server and check that the message is on the inbound pipeline
|
||||
assertThat(channel.writeInbound(httpRequest)).isTrue();
|
||||
|
||||
long inboundChannelResponse = channel.readInbound();
|
||||
assertThat(inboundChannelResponse).isEqualTo(15);
|
||||
|
||||
// we should have an outbound message in the form of a HTTP response
|
||||
assertThat(channel.outboundMessages().size()).isEqualTo(1);
|
||||
// Object response = channel.readOutbound();
|
||||
|
||||
FullHttpResponse httpResponse = channel.readOutbound();
|
||||
String httpResponseContent = httpResponse.content().toString(Charset.defaultCharset());
|
||||
assertThat(httpResponseContent).isEqualTo("15");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoChannelHandlers_testExceptionHandlingInHttpMessageHandler() {
|
||||
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new HttpMessageHandler(), new CalculatorOperationHandler());
|
||||
|
||||
final FullHttpRequest wrongHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST,
|
||||
"/calculate?a=10&b=5");
|
||||
wrongHttpRequest.headers().add("Operator", "Add");
|
||||
|
||||
assertThatThrownBy(() -> {
|
||||
// send invalid HTTP request to server and expect and error
|
||||
channel.pipeline().fireChannelRead(wrongHttpRequest);
|
||||
channel.checkException();
|
||||
}).isInstanceOf(UnsupportedOperationException.class)
|
||||
.hasMessage("HTTP method not supported");
|
||||
|
||||
FullHttpResponse errorHttpResponse = channel.readOutbound();
|
||||
String errorHttpResponseContent = errorHttpResponse.content().toString(Charset.defaultCharset());
|
||||
assertThat(errorHttpResponseContent).isEqualToIgnoringCase("Operation not defined");
|
||||
assertThat(errorHttpResponse.status()).isEqualTo(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoChannelHandlers_testExceptionHandlingInCalculatorOperationHandler() {
|
||||
EmbeddedChannel channel = new EmbeddedChannel(new HttpMessageHandler(), new CalculatorOperationHandler());
|
||||
|
||||
final FullHttpRequest wrongHttpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
|
||||
"/calculate?a=10&b=5");
|
||||
wrongHttpRequest.headers().add("Operator", "Invalid_operation");
|
||||
|
||||
// the HttpMessageHandler does not handle the exception and throws it down the pipeline
|
||||
assertThatThrownBy(() -> {
|
||||
channel.writeInbound(wrongHttpRequest);
|
||||
}).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Operation not defined");
|
||||
|
||||
// the outbound message is a HTTP response with the status code 500
|
||||
FullHttpResponse errorHttpResponse = channel.readOutbound();
|
||||
String errorHttpResponseContent = errorHttpResponse.content().toString(Charset.defaultCharset());
|
||||
assertThat(errorHttpResponseContent).isEqualToIgnoringCase("Operation not defined");
|
||||
assertThat(errorHttpResponse.status()).isEqualTo(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.baeldung.tomcat;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* Created by adi on 1/14/18.
|
||||
*/
|
||||
@RunWith(BlockJUnit4ClassRunner.class)
|
||||
public class ProgrammaticTomcatIntegrationTest {
|
||||
|
||||
private ProgrammaticTomcat tomcat = new ProgrammaticTomcat();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
tomcat.startTomcat();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
tomcat.stopTomcat();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTomcatStarted_whenAccessServlet_responseIsTestAndResponseHeaderIsSet() throws Exception {
|
||||
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
|
||||
HttpGet getServlet = new HttpGet("http://localhost:8080/my-servlet");
|
||||
|
||||
HttpResponse response = httpClient.execute(getServlet);
|
||||
assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
|
||||
|
||||
String myHeaderValue = response.getFirstHeader("myHeader").getValue();
|
||||
assertEquals("myHeaderValue", myHeaderValue);
|
||||
|
||||
HttpEntity responseEntity = response.getEntity();
|
||||
assertNotNull(responseEntity);
|
||||
|
||||
String responseString = EntityUtils.toString(responseEntity, "UTF-8");
|
||||
assertEquals("test", responseString);
|
||||
}
|
||||
|
||||
}
|
||||
BIN
libraries-server/src/test/resources/jetty-embedded-demo-app.war
Normal file
BIN
libraries-server/src/test/resources/jetty-embedded-demo-app.war
Normal file
Binary file not shown.
Reference in New Issue
Block a user