title: Netty HTTP server with Spring framework
body: <p>I am implementing a Netty application with Spring; however, my application shuts down after starting without any exception. </p>
  
  <p>My console output is:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>My code is:</p>
  
  <p><strong>IServer</strong>:</p>
  
  <pre><code>package org.crytek.server;
  
  /**
   * Created by eemrcag on 19.06.2015.
   */
  public interface IServer {
  
      public void start();
  
      public void restart();
  
      public void stop();
  }
  </code></pre>
  
  <p><strong>ServerNettyImpl</strong>:</p>
  
  <pre><code>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);
          }
      }
  }
  </code></pre>
  
  <p><strong>ServerConfig</strong>:</p>
  
  <pre><code>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();
      }
  
  }
  </code></pre>
  
  <p><strong>CryServerHandler</strong>:</p>
  
  <pre><code>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&lt;String&gt; levelList  = decoder.parameters().get("level");
              if(levelList.size() != 1)
              {
                  //error
              }else{
                  level = levelList.get(0);
              }
              List&lt;String&gt; indexList  = decoder.parameters().get("index");
              if(indexList.size() &gt; 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();
      }
  }
  </code></pre>
  
  <p><strong>CryServerInitializer</strong>:</p>
  
  <pre><code>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&lt;SocketChannel&gt; {
      @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;
      }
  }
  </code></pre>
  
  <p><strong>HelloApp</strong>:</p>
  
  <pre><code>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();
      }
  }
  </code></pre>
  
  <p>**HelloService **:</p>
  
  <pre><code>package org.crytek.server;
  
  import org.springframework.stereotype.Component;
  
  @Component
  public class HelloService {
      public String sayHello() {
          return "Hello world!";
      }
  }
  </code></pre>
  
  <p><strong>HumanPyramidCalculator</strong>: </p>
  
  <pre><code>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;
      }
  }
  </code></pre>
  
  
  
  <p><strong>cryserver.properties</strong>:</p>
  
  <pre><code>port = 8080
  boss.thread.count = 1
  </code></pre>
  
  <p><strong>spring-config.xml</strong>:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;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"&gt;
      &lt;context:annotation-config /&gt;
      &lt;context:component-scan base-package="org.crytek.server"/&gt;
  &lt;/beans&gt;
  </code></pre>
  
  <p>Any idea?</p>
  
  <p>Thanks.</p>