I am implementing a Netty application with Spring; however, my application shuts down after starting without any exception.
My console output is:
Connected to the target VM, address: '127.0.0.1:62313', transport: 'socket'
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Disconnected from the target VM, address: '127.0.0.1:62313', transport: 'socket'
Server started
Process finished with exit code 0
My code is:
IServer:
package org.crytek.server;
/**
* Created by eemrcag on 19.06.2015.
*/
public interface IServer {
public void start();
public void restart();
public void stop();
}
ServerNettyImpl:
package org.crytek.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.crytek.server.handler.CryServerInitializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.net.InetSocketAddress;
/**
* Created by eemrcag on 19.06.2015.
*/
@Component("serverNettyImpl")
public class ServerNettyImpl implements IServer{
@Autowired
@Qualifier("serverInitializer")
private CryServerInitializer serverInitializer;
@Autowired
@Qualifier("bossGroup")
private NioEventLoopGroup bossGroup;
@Autowired
@Qualifier("workerGroup")
private NioEventLoopGroup workerGroup;
@Autowired
@Qualifier("tcpSocketAddress")
private InetSocketAddress tcpSocketAddress;
private Channel channel;
@Override
public void start() {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(serverInitializer);
try {
channel = b.bind(tcpSocketAddress).sync().channel().closeFuture().channel();
System.out.println("Server started");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void restart() {
this.stop();
this.start();
}
@Override
public void stop() {
if (this.channel != null) {
this.channel.close().addListener(ChannelFutureListener.CLOSE);
}
}
}
ServerConfig:
package org.crytek.server.config;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.crytek.server.handler.CryServerInitializer;
import org.crytek.server.humanPyramid.HumanPyramidCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import java.net.InetSocketAddress;
/**
* Created by eemrcag on 17.06.2015.
*/
@Configuration
@ComponentScan("org.crytek.server")
@PropertySource("classpath:cryserver.properties")
public class ServerConfig {
@Value("${port}")
private int port;
@Value("${boss.thread.count}")
private int bossThreadCount;
@Autowired
@Qualifier("serverInitializer")
private CryServerInitializer serverInitializer;
@Bean(name = "bossGroup", destroyMethod = "shutdownGracefully")
public NioEventLoopGroup bossGroup() {
return new NioEventLoopGroup(bossThreadCount);
}
@Bean(name = "workerGroup", destroyMethod = "shutdownGracefully")
public NioEventLoopGroup workerGroup() {
return new NioEventLoopGroup();
}
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean(name = "tcpSocketAddress")
public InetSocketAddress tcpPort() {
return new InetSocketAddress(port);
}
@Bean(name = "humanPyramidCalculator")
@Scope("singleton")
public HumanPyramidCalculator humanPyramidCalculator()
{
return new HumanPyramidCalculator();
}
}
CryServerHandler:
package org.crytek.server.handler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import org.crytek.server.humanPyramid.HumanPyramidCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.List;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
/**
* Created by eemrcag on 15.06.2015.
*/
@Component("serverHandler")
@Sharable
public class CryServerHandler extends ChannelHandlerAdapter {
@Autowired
@Qualifier("humanPyramidCalculator")
private HumanPyramidCalculator humanPyramidCalculator;
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof HttpRequest)
{
HttpRequest req = (HttpRequest) msg;
String level = null;
String index = null;
//if(req.method().equals(HttpMethod.GET))
QueryStringDecoder decoder = new QueryStringDecoder(req.uri());
if(!decoder.path().equals("/humanEdgeWeight"))
{
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);
}
List<String> levelList = decoder.parameters().get("level");
if(levelList.size() != 1)
{
//error
}else{
level = levelList.get(0);
}
List<String> indexList = decoder.parameters().get("index");
if(indexList.size() > 1)
{
//error
}else{
index = indexList.get(0);
}
double result = 0.0;
if(index == null)
{
result = humanPyramidCalculator.getHumanWeight(Integer.parseInt(level));
}else{
result = humanPyramidCalculator.getHumanWeight(Integer.parseInt(level), Integer.parseInt(index));
}
ByteBuf buf = Unpooled.buffer();
ByteBufUtil.writeAscii(buf,String.valueOf(result));
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
response.headers().set(CONTENT_TYPE, "text/plain");
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
CryServerInitializer:
package org.crytek.server.handler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
/**
* Created by eemrcag on 16.06.2015.
*/
@Component("serverInitializer")
public class CryServerInitializer extends ChannelInitializer<SocketChannel> {
@Autowired
@Qualifier("serverHandler")
private CryServerHandler serverHandler;
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline p = socketChannel.pipeline();
p.addLast(new HttpServerCodec());
p.addLast(serverHandler);
}
public CryServerHandler getServerHandler() {
return serverHandler;
}
public void setServerHandler(CryServerHandler serverHandler) {
this.serverHandler = serverHandler;
}
}
HelloApp:
package org.crytek.server;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
IServer server=(IServer)context.getBean("serverNettyImpl");
server.start();
}
}
**HelloService **:
package org.crytek.server;
import org.springframework.stereotype.Component;
@Component
public class HelloService {
public String sayHello() {
return "Hello world!";
}
}
HumanPyramidCalculator:
package org.crytek.server.humanPyramid;
/**
* Created by eemrcag on 16.06.2015.
*/
public class HumanPyramidCalculator {
public static double getHumanWeight(int level)
{
return 1;
}
public static double getHumanWeight(int level, int index)
{
return 1;
}
}
cryserver.properties:
port = 8080
boss.thread.count = 1
spring-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<context:component-scan base-package="org.crytek.server"/>
</beans>
Any idea?
Thanks.
You need to end your main method or server start method with a call that blocks until shutdown. In the netty helloworld example they call channel.closeFuture().sync()