/* Copyright (c) 2001 - 2009 TOPP - www.openplans.org. All rights reserved. * This code is licensed under the GPL 2.0 license, availible at the root * application directory. */ package org.geoserver.ftp; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.ftpserver.DataConnectionConfiguration; import org.apache.ftpserver.DataConnectionConfigurationFactory; import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.FtpServerFactory; import org.apache.ftpserver.ftplet.FtpException; import org.apache.ftpserver.ftplet.Ftplet; import org.apache.ftpserver.ftplet.UserManager; import org.apache.ftpserver.listener.ListenerFactory; import org.geotools.util.logging.Logging; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextStoppedEvent; /** * Starts and stop the FTP server. * * @author Andrea Aime - OpenGeo */ public class FTPServerManager implements ApplicationListener { static final Logger LOGGER = Logging.getLogger(FTPServerManager.class); private FtpServer ftp; private UserManager userManager; private FtpLetFinder callbacks; private FTPConfigLoader loader; private FTPConfig config; /** * Sets up the {@link FtpServer FTP Server} managed by this bean using the provided * {@code userManager} * * @param userManager */ public FTPServerManager(final UserManager userManager, FtpLetFinder callbacks, FTPConfigLoader loader) { this.userManager = userManager; this.callbacks = callbacks; this.loader = loader; this.config = loader.load(); configureServer(); } /** * Creates the FTP server and sets up the FTP listeners by looking up the application context * for instances of the {@link FTPCallback} extension point. */ private void configureServer() { FtpServerFactory serverFactory = new FtpServerFactory(); ListenerFactory listenerFactory = new ListenerFactory(); DataConnectionConfigurationFactory dataConnConfigFac = new DataConnectionConfigurationFactory(); DataConnectionConfiguration connectionConfiguration = dataConnConfigFac .createDataConnectionConfiguration(); LOGGER.info("Configuring GeoServer's FTP Server..."); String passivePorts = config.getPassivePorts(); if (passivePorts != null && passivePorts.trim().length() > 0) { try { LOGGER.info("Setting FTP passive ports: " + passivePorts + ". May take a few seconds while checking if they're already bound."); dataConnConfigFac.setPassivePorts(passivePorts); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Error setting the FTP server passive ports, " + "check the ftp.xml config file. Format is '\"\"|<minPort[-maxPort]> ", e); } } String passiveAddress = config.getPassiveAddress(); if (passiveAddress == null || passiveAddress.trim().length() == 0 || FTPConfig.DEFAULT_PASSIVE_ADDRESS.equals(passiveAddress)) { LOGGER.info("Passive address is the default server address"); } else { LOGGER.info("Passive address: " + passiveAddress); dataConnConfigFac.setPassiveAddress(passiveAddress); } String pasvExternalAddress = config.getPassiveExternalAddress(); if (pasvExternalAddress == null || pasvExternalAddress.trim().length() == 0 || FTPConfig.DEFAULT_PASSIVE_ADDRESS.equals(pasvExternalAddress)) { LOGGER.info("Passive external address is the default server address"); } else { LOGGER.info("Passive external address: " + pasvExternalAddress); dataConnConfigFac.setPassiveExternalAddress(pasvExternalAddress); } // configure a listener on port 8021 LOGGER.info("FTP port: " + config.getFtpPort()); listenerFactory.setPort(config.getFtpPort()); LOGGER.info("Iddle timeout: " + config.getIdleTimeout() + "s"); listenerFactory.setIdleTimeout(config.getIdleTimeout()); String serverAddress = config.getServerAddress(); if (serverAddress == null || serverAddress.trim().length() > 0 || serverAddress.toLowerCase().equals(FTPConfig.ALL_SERVER_ADDRESSES_FLAG)) { LOGGER.info("Bound to all available network interfaces"); } else { LOGGER.info("Bound to server address: " + serverAddress); listenerFactory.setServerAddress(config.getServerAddress()); } listenerFactory.setDataConnectionConfiguration(connectionConfiguration); serverFactory.addListener("default", listenerFactory.createListener()); // link the server user management to the GS one serverFactory.setUserManager(userManager); // find out the listeners Map<String, Ftplet> ftplets = callbacks.getFtpLets(); LOGGER.info("FTPLet callbacks: " + ftplets); serverFactory.setFtplets(ftplets); // start the server ftp = serverFactory.createServer(); } public void startServer() throws FtpException { if (!config.isEnabled()) { return; } if (ftp.isStopped() || ftp.isSuspended()) { LOGGER.info("Starting GeoServer FTP Server on port " + config.getFtpPort()); ftp.start(); LOGGER.info("GeoServer FTP Server started"); } } public void stopServer() { if (!ftp.isStopped()) { LOGGER.info("Stopping GeoServer FTP Server on port " + config.getFtpPort()); ftp.stop(); LOGGER.info("GeoServer FTP Server stopped"); } } /** * Listens to the application context events in order to automatically start/stop the FTP server * upon application startup/shutdown. * * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) * @see ContextRefreshedEvent * @see ContextStoppedEvent * @see ContextClosedEvent */ public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent) { try { startServer(); } catch (FtpException e) { LOGGER.log(Level.SEVERE, "Could not start the embedded FTP server", e); } } else if (event instanceof ContextStoppedEvent || event instanceof ContextClosedEvent) { stopServer(); } } }