org.helios.octo.server.OctoServer.java Source code

Java tutorial

Introduction

Here is the source code for org.helios.octo.server.OctoServer.java

Source

/**
 * Helios, OpenSource Monitoring
 * Brought to you by the Helios Development Group
 *
 * Copyright 2013, Helios Development Group and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 
 *
 */
package org.helios.octo.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolver;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.util.internal.logging.Log4JLoggerFactory;

import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.helios.octo.server.io.SystemStreamRedirector;
import org.helios.octo.server.streams.StreamOutputAdapter;

/**
 * <p>Title: OctoServer</p>
 * <p>Description: The Octo server</p> 
 * <p>Company: Helios Development Group LLC</p>
 * @author Whitehead (nwhitehead AT heliosdev DOT org)
 * <p><code>org.helios.octo.server.OctoServer</code></p>
 */

public class OctoServer implements OctoServerMBean {
    /** The listening port */
    protected int port = -1;
    /** The interface to bind to */
    protected String address = "0.0.0.0";
    /** The ObjectName that defines the classloader to load into our scope */
    protected ObjectName classLoaderRef = null;
    /** The classloader to use for the script invocation handler */
    protected ClassLoader classLoader = null;

    /** The MBeanServer where this server is deployed  */
    protected MBeanServer server = null;

    /** Instance logger */
    protected final Logger log = Logger.getLogger(getClass());
    /** The close future for the server socket */
    protected ChannelFuture closeFuture = null;
    /** The server channel */
    protected NioServerSocketChannel serverChannel = null;
    /** The boss event loop */
    protected EventLoopGroup bossGroup = null;
    /** The worker event loop */
    protected EventLoopGroup workerGroup = null;
    /** A channel group containing all the child channels */
    protected ChannelGroup channelGroup = null;

    /** The optimized object decoder */
    protected ClassResolver classResolver = null;
    /** The optimized object encoder */
    protected ObjectEncoder objectEncoder = new ObjectEncoder();

    /** Logging handler */
    protected LoggingHandler logging = new LoggingHandler(getClass(), LogLevel.INFO);

    /** Out handler */
    protected StreamOutputAdapter outAdapter = new StreamOutputAdapter((byte) 0);
    /** Out handler */
    protected StreamOutputAdapter errAdapter = new StreamOutputAdapter((byte) 1);

    /** Invocation handler */
    protected final InvocationHandler invocationHandler = new InvocationHandler();

    public static void main(String[] args) {
        BasicConfigurator.configure();
        OctoServer server = new OctoServer();
        server.setAddress("0.0.0.0");
        server.setPort(1093);
        try {
            server.setClassLoaderRef(new ObjectName(ManagementFactory.CLASS_LOADING_MXBEAN_NAME));
            server.startService();
        } catch (Exception ex) {
            ex.printStackTrace(System.err);
        }
    }

    /**
     * <p>Starts the OctoServer</p>
     * @throws Exception Thrown on any error
     */
    protected void startService() throws Exception {
        log.info(
                "\n\t===========================================\n\tStarting OctoServer\n\t===========================================");
        InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
        initClassLoader();
        log.info("Starting listener on [" + address + ":" + port + "]");
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        channelGroup = new DefaultChannelGroup(workerGroup.next());
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .localAddress(new InetSocketAddress(address, port)).childHandler(new ChannelHandler() {
                    @Override
                    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
                        channelGroup.add(ctx.channel());
                    }

                    @Override
                    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
                        /* No Op */
                    }

                    @Override
                    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                        log.error("Exception caught in client pipeline", cause);

                    }

                }).childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        //ch.pipeline().addLast("logging", logging);
                        ch.pipeline().addLast("objectDecoder", new ObjectDecoder(classResolver));
                        //ch.pipeline().addLast("objectEncoder", objectEncoder);

                        ch.pipeline().addLast("logging", logging);

                        ch.pipeline().addLast("out", outAdapter);
                        ch.pipeline().addLast("stringEncoder", new StringEncoder());
                        //ch.pipeline().addLast("err", errAdapter);

                        ch.pipeline().addLast("invHandler", invocationHandler);
                    }
                });

        b.bind().addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture f) throws Exception {
                if (f.isSuccess()) {
                    serverChannel = (NioServerSocketChannel) f.channel();
                    closeFuture = serverChannel.closeFuture();
                    log.info("Started and listening on " + serverChannel.localAddress());
                    if (!SystemStreamRedirector.isInstalledOnCurrentThread()) {
                        SystemStreamRedirector.install();
                    }
                    log.info(
                            "\n\t===========================================\n\tStarted OctoServer\n\t===========================================");
                }
            }
        });

    }

    /**
     * <p>Stops the OctoServer</p>
     */
    protected void stopService() {
        log.info(
                "\n\t===========================================\n\tStopping OctoServer\n\t===========================================");
        if (serverChannel != null) {
            try {
                serverChannel.close().sync();
            } catch (Exception ex) {
                /* No Op */}
            serverChannel = null;
        }
        try {
            bossGroup.shutdownGracefully().sync();
        } catch (Exception ex) {
            /* No Op */}
        bossGroup = null;
        try {
            workerGroup.shutdownGracefully().sync();
        } catch (Exception ex) {
            /* No Op */}
        workerGroup = null;
        if (SystemStreamRedirector.isInstalledOnCurrentThread()) {
            SystemStreamRedirector.uninstall();
        }

        log.info(
                "\n\t===========================================\n\tStopped OctoServer\n\t===========================================");
    }

    /**
     * Initializes the class loader
     */
    protected void initClassLoader() {
        ClassLoader cl = null;
        try {
            if (server == null)
                server = ManagementFactory.getPlatformMBeanServer();
            classLoader = server.getClassLoaderFor(classLoaderRef);
            if (classLoader == null)
                classLoader = OctoServer.class.getClassLoader().getParent();
            cl = new HierarchicalClassLoader(OctoServer.class.getClassLoader(), classLoader);
            log.info("Ref ClassLoader set for [" + classLoaderRef + "] --> [" + classLoader + "]");
        } catch (Exception ex) {
            log.error("Failed to get Classloader for Ref [" + classLoaderRef + "]", ex);
            cl = OctoServer.class.getClassLoader();
        }
        classResolver = ClassResolvers.weakCachingConcurrentResolver(cl);
    }

    /**
     * Returns the listening port or -1 if the server channel is not listening
     * @return the listening port or -1
     */
    public int getPort() {
        return serverChannel == null ? -1 : serverChannel.localAddress().getPort();
    }

    /**
     * Returns the interface the listener is bound to or null if the server channel is not listening
     * @return the interface the listener is bound to
     */
    public String getAddress() {
        return serverChannel == null ? null : serverChannel.localAddress().getHostName();
    }

    /**
     * Sets the port to listen on 
     * @param port the port to listen on
     */
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * Returns the class loader ref object name
     * @return the class loader ref object name
     */
    public ObjectName getClassLoaderRef() {
        return classLoaderRef;
    }

    /**
     * Sets the class loader ref object name
     * @param classLoaderRef the classLoaderRef to set
     */
    public void setClassLoaderRef(ObjectName classLoaderRef) {
        this.classLoaderRef = classLoaderRef;
    }

    /**
     * Sets the interface the listener should bind to
     * @param address the address to set
     */
    public void setAddress(String address) {
        this.address = address;
    }

}