/**
 *
 */
package com.lafaspot.pop.client;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nonnull;
import javax.net.ssl.SSLException;

import com.lafaspot.logfast.logging.LogContext;
import com.lafaspot.logfast.logging.LogManager;
import com.lafaspot.logfast.logging.Logger;
import com.lafaspot.pop.exception.PopException;
import com.lafaspot.pop.session.PopSession;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;

/**
 * POP client that supports secure connection and POP3 protocol.
 *
 * @author kraman
 *
 */
public class PopClient {

    /** instance id used for debug. */
    private final String instanceId = Integer.toString(new Random(System.nanoTime()).nextInt());

    /** counter for sessions. */
    private AtomicInteger sessionCounter = new AtomicInteger(1);

    /** The netty bootstrap. */
    private final Bootstrap bootstrap;

    /** Event loop group that will serve all channels for IMAP client. */
    private final EventLoopGroup group;

    /** The log manger. */
    private final LogManager logManager;

    /** The logger. */
    private Logger logger;

    private final SslContext sslContext;
    /**
     * Constructor to create a new POP client.
     *
     * @param threads number of threads to use
     * @param logManager the log manager
     * @throws PopException on failure
     */
    public PopClient(final int threads, @Nonnull final LogManager logManager) throws PopException {

        this.logManager = logManager;
        LogContext context = new SessionLogContext("PopClient");
        this.logger = logManager.getLogger(context);

        this.bootstrap = new Bootstrap();
        this.group = new NioEventLoopGroup(threads);
        try {
            this.sslContext = SslContextBuilder.forClient().build();
            bootstrap.group(group);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true); // (4)
        } catch (SSLException e) {
            throw new PopException(PopException.Type.INTERNAL_FAILURE, e);
        }
    }

    /**
     * Create PopSession.
     * 
     * @return PopSession
     */
    public PopSession createSession() {
        return new PopSession(sslContext, bootstrap, logger);
    }

    /**
     * Shut down the pop client.
     */
    public void shutdown() {
        this.group.shutdownGracefully();
    }
}

@@ -63,16 +63,54 @@
 Random;%0A
+import java.util.concurrent.TimeUnit;%0A
 import j
@@ -151,16 +151,16 @@
 nteger;%0A
-
 %0Aimport 
@@ -1022,107 +1022,8 @@
 );%0A%0A
-    /** counter for sessions. */%0A    private AtomicInteger sessionCounter = new AtomicInteger(1);%0A%0A
     
@@ -1321,24 +1321,52 @@
 er logger;%0A%0A
+    /** The SSL context. */%0A
     private 
@@ -1394,16 +1394,246 @@
 ontext;%0A
+    %0A    /** The quit period time for shutdown. */%0A    private static final long SHUTDOWN_QUIET_PERIOD_MILLIS = 5000L;%0A    %0A    /** The timeout for shutdown. */%0A    private static final long SHUTDOWN_TIMEOUT_MILLIS = 30000L;%0A    %0A
     /**%0A
@@ -2261,32 +2261,37 @@
 ();%0A            
+this.
 bootstrap.group(
@@ -2290,16 +2290,21 @@
 p.group(
+this.
 group);%0A
@@ -2307,32 +2307,37 @@
 p);%0A            
+this.
 bootstrap.channe
@@ -2375,16 +2375,21 @@
         
+this.
 bootstra
@@ -2456,16 +2456,22 @@
  catch (
+final 
 SSLExcep
@@ -2718,16 +2718,21 @@
 Session(
+this.
 sslConte
@@ -2735,16 +2735,21 @@
 ontext, 
+this.
 bootstra
@@ -2751,16 +2751,21 @@
 tstrap, 
+this.
 logger);
@@ -2846,24 +2846,24 @@
 hutdown() %7B%0A
-
         this
@@ -2888,16 +2888,92 @@
 cefully(
+SHUTDOWN_QUIET_PERIOD_MILLIS, SHUTDOWN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS
 );%0A    %7D

Add timeout for client shutdown