jgnash.engine.attachment.AttachmentTransferServer.java Source code

Java tutorial

Introduction

Here is the source code for jgnash.engine.attachment.AttachmentTransferServer.java

Source

/*
 * jGnash, a personal finance application
 * Copyright (C) 2001-2015 Craig Cavanaugh
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package jgnash.engine.attachment;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
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.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.base64.Base64Decoder;
import io.netty.handler.codec.base64.Base64Encoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;

import jgnash.util.EncryptionManager;

import static jgnash.engine.attachment.NettyTransferHandler.PATH_MAX;
import static jgnash.engine.attachment.NettyTransferHandler.TRANSFER_BUFFER_SIZE;

/**
 * File server for attachments.
 *
 * @author Craig Cavanaugh
 */
public class AttachmentTransferServer {

    private static final Logger logger = Logger.getLogger(AttachmentTransferServer.class.getName());

    private final int port;

    private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

    private final ChannelGroup channelGroup = new DefaultChannelGroup("file-server", GlobalEventExecutor.INSTANCE);

    private final Path attachmentPath;

    private EncryptionManager encryptionManager = null;

    public AttachmentTransferServer(final int port, final Path attachmentPath) {
        this.port = port;
        this.attachmentPath = attachmentPath;
    }

    public boolean startServer(final char[] password) {
        boolean result = false;

        // If a password has been specified, create an EncryptionManager
        if (password != null && password.length > 0) {
            encryptionManager = new EncryptionManager(password);
        }

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(eventLoopGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        @Override
                        public void initChannel(final SocketChannel ch) throws Exception {

                            ch.pipeline().addLast(
                                    new DelimiterBasedFrameDecoder(((TRANSFER_BUFFER_SIZE + 2) / 3) * 4 + PATH_MAX,
                                            true, Delimiters.lineDelimiter()),

                                    new StringEncoder(CharsetUtil.UTF_8), new StringDecoder(CharsetUtil.UTF_8),

                                    new Base64Encoder(), new Base64Decoder(),

                                    new ServerTransferHandler());
                        }
                    });

            // Start the server.
            final ChannelFuture future = b.bind(port).sync();

            if (future.isDone() && future.isSuccess()) {
                result = true;
                logger.info("File Transfer Server started successfully");
            } else {
                logger.info("Failed to start the File Transfer Server");
            }
        } catch (final InterruptedException e) {
            logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
            stopServer();
        }

        return result;
    }

    public void stopServer() {
        try {
            channelGroup.close().sync();

            eventLoopGroup.shutdownGracefully();

            logger.info("File Transfer Server stopped");
        } catch (final InterruptedException e) {
            logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
        }
    }

    private final class ServerTransferHandler extends NettyTransferHandler {

        public ServerTransferHandler() {
            super(attachmentPath, encryptionManager);
        }

        @Override
        public void channelActive(final ChannelHandlerContext ctx) throws Exception {
            channelGroup.add(ctx.channel()); // maintain channels

            logger.log(Level.INFO, "Remote connection from: {0}", ctx.channel().remoteAddress().toString());
        }
    }
}