Refactor LISP package to separate ctrl interface and impl classes

Change-Id: I4e94ff54299e886cd0e8b3ce38591b0900290f54
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java
new file mode 100644
index 0000000..29af596
--- /dev/null
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispControllerBootstrap.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.lisp.ctl.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.PooledByteBufAllocator;
+import io.netty.channel.AbstractChannel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.EpollDatagramChannel;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+import java.util.List;
+
+/**
+ * Bootstraps LISP netty channel, handles all setup and network listeners.
+ */
+public class LispControllerBootstrap {
+
+    protected static final Logger log = LoggerFactory.getLogger(LispControllerBootstrap.class);
+
+    private static final int LISP_DATA_PORT = 4341;
+    private static final int LISP_CONTROL_PORT = 4342;
+
+    // Configuration options
+    protected List<Integer> lispPorts = ImmutableList.of(LISP_DATA_PORT, LISP_CONTROL_PORT);
+
+    private EventLoopGroup eventLoopGroup;
+    private Class<? extends AbstractChannel> channelClass;
+
+    /**
+     * Stitches all channel handlers into server bootstrap.
+     */
+    private void run() {
+
+        try {
+            final Bootstrap bootstrap = createServerBootstrap();
+
+            configBootstrapOptions(bootstrap);
+
+            List<ChannelFuture> channelFutures = Lists.newArrayList();
+
+            lispPorts.forEach(p -> {
+                InetSocketAddress sa = new InetSocketAddress(p);
+                channelFutures.add(bootstrap.bind(sa));
+                log.info("Listening for LISP router connections on {}", sa);
+            });
+
+            for (ChannelFuture f : channelFutures) {
+                f.sync();
+            }
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Initializes server bootstrap with given LISP channel initializer.
+     *
+     * @return initialized server bootstrap
+     */
+    private Bootstrap createServerBootstrap() {
+        Bootstrap bootstrap = new Bootstrap();
+
+        initEventLoopGroup();
+        bootstrap.group(eventLoopGroup)
+                .channel(channelClass)
+                .handler(new LispChannelInitializer());
+
+        return bootstrap;
+    }
+
+    /**
+     * Configures bootstrap options to tune the communication performance.
+     *
+     * @param bootstrap LISP server bootstrap
+     */
+    private void configBootstrapOptions(Bootstrap bootstrap) {
+        bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
+    }
+
+    /**
+     * Closes all open channels.
+     *
+     * @param channelFutures a collection of channel futures
+     */
+    private void closeChannels(List<ChannelFuture> channelFutures) {
+        try {
+            for (ChannelFuture f : channelFutures) {
+                f.channel().closeFuture().sync();
+            }
+        } catch (InterruptedException e) {
+            log.warn("Failed to close channels. Reasons: {}.", e.getMessage());
+        }
+    }
+
+    /**
+     * Initializes event loop group.
+     */
+    private void initEventLoopGroup() {
+
+        // try to use EpollEventLoopGroup if possible,
+        // if OS does not support native Epoll, fallback to use netty NIO
+        try {
+            eventLoopGroup = new EpollEventLoopGroup();
+            channelClass = EpollDatagramChannel.class;
+        } catch (Throwable e) {
+            log.debug("Failed to initialize native (epoll) transport. "
+                        + "Reason: {}. Proceeding with NIO event group.", e.getMessage());
+        }
+        eventLoopGroup = new NioEventLoopGroup();
+        channelClass = NioDatagramChannel.class;
+    }
+
+    /**
+     * Launches LISP controller to listen control channel.
+     */
+    public void start() {
+        log.info("Starting LISP control I/O");
+
+        this.run();
+    }
+
+    /**
+     * Terminates LISP controller and lease all occupied resources.
+     */
+    public void stop() {
+        log.info("Stopping LISP control I/O");
+
+        try {
+            // try to shutdown all open event groups
+            eventLoopGroup.shutdownGracefully().sync();
+        } catch (InterruptedException e) {
+            log.warn("Failed to stop LISP controller. Reasons: {}.", e.getMessage());
+        }
+    }
+}