2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.ftpupload.internal.ftp;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
19 import java.util.List;
22 import org.apache.ftpserver.FtpServerConfigurationException;
23 import org.apache.ftpserver.FtpServerFactory;
24 import org.apache.ftpserver.ftplet.DefaultFtplet;
25 import org.apache.ftpserver.ftplet.FileSystemFactory;
26 import org.apache.ftpserver.ftplet.FileSystemView;
27 import org.apache.ftpserver.ftplet.FtpException;
28 import org.apache.ftpserver.ftplet.FtpRequest;
29 import org.apache.ftpserver.ftplet.FtpSession;
30 import org.apache.ftpserver.ftplet.FtpStatistics;
31 import org.apache.ftpserver.ftplet.Ftplet;
32 import org.apache.ftpserver.ftplet.FtpletContext;
33 import org.apache.ftpserver.ftplet.FtpletResult;
34 import org.apache.ftpserver.ftplet.User;
35 import org.apache.ftpserver.listener.Listener;
36 import org.apache.ftpserver.listener.ListenerFactory;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * Simple FTP server implementation to receive files via FTP.
44 * @author Pauli Anttila - Initial contribution
46 public class FtpServer {
48 private final Logger logger = LoggerFactory.getLogger(FtpServer.class);
53 private org.apache.ftpserver.FtpServer server;
54 private List<FtpServerEventListener> listeners;
55 private MyFTPLet myFTPLet;
56 private FTPUserManager FTPUserManager;
57 private String ftpStartUpErrorReason;
60 listeners = new ArrayList<>();
61 FTPUserManager = new FTPUserManager();
64 public void startServer(int port, int idleTimeout) throws FtpException {
67 this.idleTimeout = idleTimeout;
68 FTPUserManager.setIdleTimeout(idleTimeout);
72 public void stopServer() {
78 public String getStartUpErrorReason() {
79 return ftpStartUpErrorReason;
82 public synchronized void addEventListener(FtpServerEventListener listener) {
83 if (!listeners.contains(listener)) {
84 listeners.add(listener);
88 public synchronized void addAuthenticationCredentials(String username, String password)
89 throws IllegalArgumentException {
90 FTPUserManager.addAuthenticationCredentials(username, password);
93 public synchronized void removeAuthenticationCredentials(String username) {
94 FTPUserManager.removeAuthenticationCredentials(username);
97 public synchronized void removeEventListener(FtpServerEventListener listener) {
98 listeners.remove(listener);
101 private void sendMsgToListeners(String userName, String filename, byte[] data) {
102 Iterator<FtpServerEventListener> iterator = listeners.iterator();
104 while (iterator.hasNext()) {
106 iterator.next().fileReceived(userName, filename, data);
107 } catch (Exception e) {
108 // catch all exceptions give all handlers a fair chance of handling the messages
109 logger.debug("Event listener invoking error: {}", e.getMessage());
114 public void printStats() {
115 FtpStatistics ftpStats = myFTPLet.getStats();
117 logger.debug("TotalConnectionNumber: {}", ftpStats.getTotalConnectionNumber());
118 logger.debug("TotalLoginNumber: {}", ftpStats.getTotalLoginNumber());
119 logger.debug("TotalFailedLoginNumber: {}", ftpStats.getTotalFailedLoginNumber());
120 logger.debug("TotalUploadNumber: {}", ftpStats.getTotalUploadNumber());
121 logger.debug("TotalUploadSize: {}", ftpStats.getTotalUploadSize());
123 logger.debug("CurrentConnectionNumber: {}", ftpStats.getCurrentConnectionNumber());
124 logger.debug("CurrentLoginNumber: {}", ftpStats.getCurrentLoginNumber());
127 private void initServer() throws FtpException {
128 FtpServerFactory serverFactory = new FtpServerFactory();
129 ListenerFactory listenerFactory = new ListenerFactory();
130 listenerFactory.setPort(port);
131 listenerFactory.setIdleTimeout(idleTimeout);
133 Listener listener = listenerFactory.createListener();
135 serverFactory.addListener("default", listener);
137 Map<String, Ftplet> ftplets = new LinkedHashMap<>();
138 myFTPLet = new MyFTPLet();
140 ftplets.put("ftplet", myFTPLet);
142 serverFactory.setFtplets(ftplets);
143 serverFactory.setFileSystem(new FileSystemFactory() {
145 public FileSystemView createFileSystemView(User user) throws FtpException {
146 logger.debug("createFileSystemView: {}", user.getName());
147 return new SimpleFileSystemView();
151 // set the user manager
152 serverFactory.setUserManager(FTPUserManager);
153 server = serverFactory.createServer();
157 ftpStartUpErrorReason = null;
158 } catch (FtpException | FtpServerConfigurationException e) {
159 ftpStartUpErrorReason = "Failed to start FTP server";
160 if (!e.getMessage().isEmpty()) {
161 ftpStartUpErrorReason += ": " + e.getMessage();
167 private class MyFTPLet extends DefaultFtplet {
168 FtpletContext ftpletContext;
170 public FtpStatistics getStats() {
171 return ftpletContext.getFtpStatistics();
175 public void init(FtpletContext ftpletContext) throws FtpException {
176 this.ftpletContext = ftpletContext;
180 public void destroy() {
181 logger.trace("destroy");
185 public FtpletResult onConnect(FtpSession session) throws FtpException, IOException {
186 logger.debug("User connected to FtpServer");
187 return super.onConnect(session);
191 public FtpletResult onUploadEnd(final FtpSession session, final FtpRequest request)
192 throws FtpException, IOException {
193 String userRoot = session.getUser().getHomeDirectory();
194 String currDir = session.getFileSystemView().getWorkingDirectory().getAbsolutePath();
195 String fileName = request.getArgument();
197 logger.debug("File {} upload to FTP server", userRoot + currDir + "/" + fileName);
199 SimpleFtpFile file = (SimpleFtpFile) session.getFileSystemView().getFile(fileName);
200 byte[] data = file.getData();
202 sendMsgToListeners(session.getUser().getName(), fileName, data);
203 return FtpletResult.SKIP;