]> git.basschouten.com Git - openhab-addons.git/blob
df1444f85a912786c3561870ed7d7747f8dbedde
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.ftpupload.internal.ftp;
14
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;
20 import java.util.Map;
21
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;
39
40 /**
41  * Simple FTP server implementation to receive files via FTP.
42  *
43  *
44  * @author Pauli Anttila - Initial contribution
45  */
46 public class FtpServer {
47
48     private final Logger logger = LoggerFactory.getLogger(FtpServer.class);
49
50     private int port;
51     int idleTimeout;
52
53     private org.apache.ftpserver.FtpServer server;
54     private List<FtpServerEventListener> listeners;
55     private MyFTPLet myFTPLet;
56     private FTPUserManager FTPUserManager;
57     private String ftpStartUpErrorReason;
58
59     public FtpServer() {
60         listeners = new ArrayList<>();
61         FTPUserManager = new FTPUserManager();
62     }
63
64     public void startServer(int port, int idleTimeout) throws FtpException {
65         stopServer();
66         this.port = port;
67         this.idleTimeout = idleTimeout;
68         FTPUserManager.setIdleTimeout(idleTimeout);
69         initServer();
70     }
71
72     public void stopServer() {
73         if (server != null) {
74             server.stop();
75         }
76     }
77
78     public String getStartUpErrorReason() {
79         return ftpStartUpErrorReason;
80     }
81
82     public synchronized void addEventListener(FtpServerEventListener listener) {
83         if (!listeners.contains(listener)) {
84             listeners.add(listener);
85         }
86     }
87
88     public synchronized void addAuthenticationCredentials(String username, String password)
89             throws IllegalArgumentException {
90         FTPUserManager.addAuthenticationCredentials(username, password);
91     }
92
93     public synchronized void removeAuthenticationCredentials(String username) {
94         FTPUserManager.removeAuthenticationCredentials(username);
95     }
96
97     public synchronized void removeEventListener(FtpServerEventListener listener) {
98         listeners.remove(listener);
99     }
100
101     private void sendMsgToListeners(String userName, String filename, byte[] data) {
102         Iterator<FtpServerEventListener> iterator = listeners.iterator();
103
104         while (iterator.hasNext()) {
105             try {
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());
110             }
111         }
112     }
113
114     public void printStats() {
115         FtpStatistics ftpStats = myFTPLet.getStats();
116
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());
122
123         logger.debug("CurrentConnectionNumber: {}", ftpStats.getCurrentConnectionNumber());
124         logger.debug("CurrentLoginNumber: {}", ftpStats.getCurrentLoginNumber());
125     }
126
127     private void initServer() throws FtpException {
128         FtpServerFactory serverFactory = new FtpServerFactory();
129         ListenerFactory listenerFactory = new ListenerFactory();
130         listenerFactory.setPort(port);
131         listenerFactory.setIdleTimeout(idleTimeout);
132
133         Listener listener = listenerFactory.createListener();
134
135         serverFactory.addListener("default", listener);
136
137         Map<String, Ftplet> ftplets = new LinkedHashMap<>();
138         myFTPLet = new MyFTPLet();
139
140         ftplets.put("ftplet", myFTPLet);
141
142         serverFactory.setFtplets(ftplets);
143         serverFactory.setFileSystem(new FileSystemFactory() {
144             @Override
145             public FileSystemView createFileSystemView(User user) throws FtpException {
146                 logger.debug("createFileSystemView: {}", user.getName());
147                 return new SimpleFileSystemView();
148             }
149         });
150
151         // set the user manager
152         serverFactory.setUserManager(FTPUserManager);
153         server = serverFactory.createServer();
154
155         try {
156             server.start();
157             ftpStartUpErrorReason = null;
158         } catch (FtpException | FtpServerConfigurationException e) {
159             ftpStartUpErrorReason = "Failed to start FTP server";
160             if (!e.getMessage().isEmpty()) {
161                 ftpStartUpErrorReason += ": " + e.getMessage();
162             }
163             throw e;
164         }
165     }
166
167     private class MyFTPLet extends DefaultFtplet {
168         FtpletContext ftpletContext;
169
170         public FtpStatistics getStats() {
171             return ftpletContext.getFtpStatistics();
172         }
173
174         @Override
175         public void init(FtpletContext ftpletContext) throws FtpException {
176             this.ftpletContext = ftpletContext;
177         }
178
179         @Override
180         public void destroy() {
181             logger.trace("destroy");
182         }
183
184         @Override
185         public FtpletResult onConnect(FtpSession session) throws FtpException, IOException {
186             logger.debug("User connected to FtpServer");
187             return super.onConnect(session);
188         }
189
190         @Override
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();
196
197             logger.debug("File {} upload to FTP server", userRoot + currDir + "/" + fileName);
198
199             SimpleFtpFile file = (SimpleFtpFile) session.getFileSystemView().getFile(fileName);
200             byte[] data = file.getData();
201
202             sendMsgToListeners(session.getUser().getName(), fileName, data);
203             return FtpletResult.SKIP;
204         }
205     }
206 }