com.apporiented.hermesftp.FtpServerApp.java Source code

Java tutorial

Introduction

Here is the source code for com.apporiented.hermesftp.FtpServerApp.java

Source

/*
 * ------------------------------------------------------------------------------
 * Hermes FTP Server
 * Copyright (c) 2005-2014 Lars Behnke
 * ------------------------------------------------------------------------------
 * 
 * This file is part of Hermes FTP Server.
 * 
 * Hermes FTP Server 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 2 of the License, or
 * (at your option) any later version.
 * 
 * Hermes FTP Server 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 Hermes FTP Server; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ------------------------------------------------------------------------------
 */

package com.apporiented.hermesftp;

import java.io.File;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.apporiented.hermesftp.common.BeanConstants;
import com.apporiented.hermesftp.common.FtpConstants;
import com.apporiented.hermesftp.common.FtpServerOptions;
import com.apporiented.hermesftp.console.ConsoleServer;
import com.apporiented.hermesftp.server.FtpServer;
import com.apporiented.hermesftp.utils.IOUtils;
import com.apporiented.hermesftp.utils.NetUtils;
import com.apporiented.hermesftp.utils.SecurityUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * Hermes FTP application.
 * 
 * @author Lars Behnke
 */
public final class FtpServerApp {

    //private static final int THREAD_ALIVE_CHECK_INTERVAL = 1000;

    private static final int PASSWORD_ARG_COUNT = 3;

    private static Log log = LogFactory.getLog(FtpServerApp.class);

    /**
     * Constructor.
     */
    public FtpServerApp() {
        super();
    }

    /**
     * Entry point of the application.
     * 
     * @param args Optionally the bean resource file can be passed.
     */
    public static void main(String[] args) {
        // TODO Use commons-cli
        if (args.length > 0 && args[0].trim().equalsIgnoreCase("-password")) {
            generatePassword(args);
        } else {
            log.info("Starting Hermes FTP Server...");
            PluginManager.startApplication(FtpServerApp.class.getName(), "startServer", args);
            log.info("Hermes FTP Server ready.");
        }
    }

    private static void generatePassword(String[] args) {
        if (args.length != PASSWORD_ARG_COUNT) {
            System.err.println(
                    "Please adhere to the following synthax: FtpServerApp password <password> <algorithm>");
            return;
        }
        String password = args[1];
        String algorithm = args[2];
        try {
            String hash = SecurityUtil.digestPassword(password, algorithm);
            System.out.print("Hash: " + hash + "\n");
        } catch (NoSuchAlgorithmException e) {
            System.err.println("ERROR: " + e);
        }
    }

    /**
     * Starts the FTP servers(s).
     * 
     * @param args The arguments passed with main method.
     */
    public void startServer(String[] args) {
        if (!NetUtils.isSSLAvailable()) {
            System.exit(1);
        }
        String beanRes = args.length > 0 ? args[0] : FtpConstants.DEFAULT_BEAN_RES;
        File file = new File(beanRes);

        logPaths(file);

        /* Prepare three main threads */
        ApplicationContext appContext = getApplicationContext(beanRes, file);
        FtpServer svr = (FtpServer) appContext.getBean(BeanConstants.BEAN_SERVER);
        FtpServer sslsvr = (FtpServer) appContext.getBean(BeanConstants.BEAN_SSL_SERVER);
        ConsoleServer console = (ConsoleServer) appContext.getBean(BeanConstants.BEAN_CONSOLE);

        /* Log settings */

        logOptions(svr.getOptions());

        /* Check local ip addresses */
        InetAddress addr = NetUtils.getMachineAddress(true);
        if (addr == null) {
            log.error("No local network ip address available.");
            System.exit(1);
        }
        log.info("Local ip address: " + addr);

        /* Start servers */
        Thread svrThread;
        Thread sslSvrThread;
        try {
            svrThread = new Thread(svr);
            svrThread.start();
            sslSvrThread = new Thread(sslsvr);
            sslSvrThread.start();

            /* Start web console */
            if (svr.getOptions().getBoolean("console.enabled", false)) {
                console.start();
            }

            /* Register Shutdown Hook */
            List<FtpServer> serverList = new ArrayList<FtpServer>();
            serverList.add(svr);
            serverList.add(sslsvr);
            addShutdownHook(serverList);

        } catch (Exception e) {
            log.error("Unexpected error", e);
        }
    }

    /**
     * Add shutdown hook.
     */
    private static void addShutdownHook(final List<FtpServer> servers) {

        Runnable shutdownHook = new Runnable() {
            public void run() {
                for (FtpServer ftpServer : servers) {
                    log.info("Stopping server '" + ftpServer.getName() + "'.");
                    ftpServer.abort();
                }
                log.info("All servers down.");
            }
        };
        Runtime runtime = Runtime.getRuntime();
        runtime.addShutdownHook(new Thread(shutdownHook));
    }

    private void logPaths(File file) {
        log.info("Hermes Home: " + IOUtils.getHomeDir());

        log.info("Application context: " + file);
        if (file != null && file.getParent() != null) {
            System.setProperty("hermes.ctx.dir", file.getParent());
            log.info("Application context path: " + file.getParent());
        }
    }

    private static ApplicationContext getApplicationContext(String beanRes, File file) {
        ApplicationContext appContext;
        if (file.exists()) {
            appContext = new FileSystemXmlApplicationContext(new String[] { beanRes });
        } else {
            log.error("Hermes FTP application context not found: " + file
                    + ". Trying to read context from classpath...");
            appContext = new ClassPathXmlApplicationContext(new String[] { "/" + FtpConstants.DEFAULT_BEAN_RES });
        }
        return appContext;
    }

    private static void logOptions(FtpServerOptions aOptions) {
        log.info(aOptions.getAppTitle());
        log.info("Version " + aOptions.getAppVersion());
        log.info("Build info: " + aOptions.getAppBuildInfo());
        log.info("OS name: " + System.getProperty("os.name"));
        log.info("OS file encoding (System): " + System.getProperty("file.encoding"));
        log.info("OS file encoding (NIO): " + Charset.defaultCharset().name());
        log.info("Ftp server options:");
        Set<Object> keyset = aOptions.getProperties().keySet();
        for (Object key : keyset) {
            String value = aOptions.getProperty(key.toString());
            log.info("    " + key + ": " + value);
        }
    }
}