[BAEL-8499] - Moved server related codes / articles to libraries-server module

This commit is contained in:
amit2103
2018-09-01 14:51:03 +05:30
parent de84251d48
commit fc69e1257b
34 changed files with 77 additions and 37 deletions

View 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)

View File

@@ -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>

View File

@@ -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();
}
});
}
}

View File

@@ -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\"}");
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}

View File

@@ -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 + '\'' +
'}';
}
}

View File

@@ -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);
}
}

View File

@@ -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 + '\'' + '}';
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 + '}';
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}
}

View File

@@ -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() {
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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");
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}