001: /**
002: *
003: * Copyright (C) 2007 Enterprise Distributed Technologies Ltd
004: *
005: * www.enterprisedt.com
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: *
021: * Bug fixes, suggestions and comments should be should posted on
022: * http://www.enterprisedt.com/forums/index.php
023: *
024: * Change Log:
025: *
026: * $Log: FileTransferClient.java,v $
027: * Revision 1.3 2008-01-09 03:54:21 bruceb
028: * executeCommand() now returns reply code
029: *
030: * Revision 1.2 2007-12-20 00:40:16 bruceb
031: * autologin
032: *
033: * Revision 1.1 2007-12-18 07:52:06 bruceb
034: * 2.0 changes
035: *
036: *
037: */package com.enterprisedt.net.ftp;
038:
039: import java.io.IOException;
040: import java.text.ParseException;
041: import java.util.Date;
042:
043: import com.enterprisedt.util.debug.Logger;
044:
045: /**
046: * Easy to use FTP client that is thread safe and provides true FTP streams.
047: * This class is intended to replace FTPClient, which will eventually be
048: * deprecated.
049: *
050: * @author Bruce Blackshaw
051: * @version $Revision: 1.3 $
052: */
053: public class FileTransferClient {
054:
055: private Logger log = Logger.getLogger("FileTransferClient");
056:
057: /**
058: * Context for the client that is the starting point for all
059: * new tasks. If we have a change directory task, when it is completed
060: * it will update this master context and the updated context will be used
061: * for all future tasks
062: */
063: protected ConnectionContext masterContext = new ConnectionContext();
064:
065: protected EventAggregator eventAggregator = null;
066:
067: /**
068: * Event listeners
069: */
070: protected EventListener listener;
071:
072: /**
073: * Instance of FTPClient
074: */
075: private FTPClient ftpClient = new FTPClient();
076:
077: /**
078: * Advanced configuration parameters that often aren't used
079: */
080: private AdvancedFTPSettings advancedSettings;
081:
082: private FileStatistics statistics;
083:
084: /**
085: * Default constructor
086: */
087: public FileTransferClient() {
088: advancedSettings = new AdvancedFTPSettings(masterContext);
089: statistics = new FileStatistics(ftpClient);
090: }
091:
092: /**
093: * Checks if the client has connected to the server and throws an exception if it hasn't.
094: * This is only intended to be used by subclasses
095: *
096: * @throws FTPException Thrown if the client has not connected to the server.
097: */
098: protected void checkConnection(boolean shouldBeConnected)
099: throws FTPException {
100: if (shouldBeConnected && !isConnected())
101: throw new FTPException(
102: "The file transfer client has not yet connected to the server. "
103: + "The requested action cannot be performed until after a connection has been established.");
104: else if (!shouldBeConnected && isConnected())
105: throw new FTPException(
106: "The file transfer client has already been connected to the server. "
107: + "The requested action must be performed before a connection is established.");
108: }
109:
110: /**
111: * Is this client currently connected to the server?
112: *
113: * @return true if connected, false otherwise
114: */
115: public synchronized boolean isConnected() {
116: return ftpClient.connected();
117: }
118:
119: /**
120: * Returns the IP address or name of the remote host.
121: *
122: * @return Returns the remote host.
123: */
124: public synchronized String getRemoteHost() {
125: return masterContext.getRemoteHost();
126: }
127:
128: /**
129: * Set the IP address or name of the remote host
130: *
131: * This may only be done if the client is not already connected to the server.
132: *
133: * @param remoteHost The IP address or name of the remote host
134: * @throws FTPException Thrown if the client is already connected to the server.
135: */
136: public synchronized void setRemoteHost(String remoteHost)
137: throws FTPException {
138: checkConnection(false);
139: masterContext.setRemoteHost(remoteHost);
140: }
141:
142: /**
143: * Returns the timeout for socket connections.
144: *
145: * @return Returns the connection timeout in milliseconds
146: */
147: public synchronized int getTimeout() {
148: return masterContext.getTimeout();
149: }
150:
151: /**
152: * Set the timeout for socket connections. Can only do this if
153: * not already connected.
154: *
155: * @param timeout the timeout to use in milliseconds
156: * @throws FTPException Thrown if the client is already connected to the server.
157: */
158: public synchronized void setTimeout(int timeout)
159: throws FTPException {
160: checkConnection(false);
161: masterContext.setTimeout(timeout);
162: }
163:
164: /**
165: * Returns the port being connected to on the remote server.
166: *
167: * @return Returns the port being connected to on the remote server.
168: */
169: public synchronized int getRemotePort() {
170: return masterContext.getRemotePort();
171: }
172:
173: /**
174: * Set the port to connect to on the remote server. Can only do this if
175: * not already connected.
176: *
177: * @param remotePort The port to use.
178: * @throws FTPException Thrown if the client is already connected to the server.
179: */
180: public synchronized void setRemotePort(int remotePort)
181: throws FTPException {
182: checkConnection(false);
183: masterContext.setRemotePort(remotePort);
184: }
185:
186: /**
187: * Set the transfer type for all connections, either ASCII or binary. Setting
188: * applies to all subsequent transfers that are initiated.
189: *
190: * @param type transfer type
191: * @throws FTPException
192: * @throws IOException
193: * @throws FTPException
194: */
195: public synchronized void setContentType(FTPTransferType type)
196: throws IOException, FTPException {
197: masterContext.setContentType(type);
198: if (ftpClient.connected())
199: ftpClient.setType(type);
200: }
201:
202: /**
203: * Get the current content type for all connections.
204: *
205: * @return transfer type
206: */
207: public synchronized FTPTransferType getContentType() {
208: return masterContext.getContentType();
209: }
210:
211: /**
212: * Set auto detect of filetypes on or off. If on, the transfer mode is
213: * switched from ASCII to binary and vice versa depending on the extension
214: * of the file. After the transfer, the mode is always returned to what it
215: * was before the transfer was performed. The default is off.
216: *
217: * If the filetype is unknown, the transfer mode is unchanged
218: *
219: * @param detectContentType true if detecting content type, false if not
220: */
221: public void setDetectContentType(boolean detectContentType) {
222: masterContext.setDetectContentType(detectContentType);
223: ftpClient.setDetectTransferMode(detectContentType);
224: }
225:
226: /**
227: * Get the detect content type flag
228: *
229: * @return true if we are detecting binary and ASCII transfers from the file type
230: */
231: public boolean getDetectContentType() {
232: return masterContext.getDetectContentType();
233: }
234:
235: /**
236: * Set the name of the user to log in with. Can only do this if
237: * not already connected.
238: *
239: * @param userName user-name to log in with.
240: * @throws FTPException
241: */
242: public synchronized void setUserName(String userName)
243: throws FTPException {
244: checkConnection(false);
245: masterContext.setUserName(userName);
246: }
247:
248: /**
249: * Get the current user password.
250: *
251: * @return current user password
252: */
253: public synchronized String getPassword() {
254: return masterContext.getPassword();
255: }
256:
257: /**
258: * Set the password of the user to log in with. Can only do this if
259: * not already connected.
260: *
261: * @param password password to log in with.
262: * @throws FTPException
263: */
264: public synchronized void setPassword(String password)
265: throws FTPException {
266: checkConnection(false);
267: masterContext.setPassword(password);
268: }
269:
270: /**
271: * Get the current user name.
272: *
273: * @return current user name
274: */
275: public synchronized String getUserName() {
276: return masterContext.getUserName();
277: }
278:
279: /**
280: * Get the advanced configuration parameters object
281: *
282: * @return advanced parameters
283: */
284: public synchronized AdvancedFTPSettings getAdvancedFTPSettings() {
285: return advancedSettings;
286: }
287:
288: /**
289: * Set the event listener for transfer event notification
290: *
291: * @param listener event listener reference
292: */
293: public synchronized void setEventListener(EventListener listener) {
294: this .listener = listener;
295: eventAggregator = new EventAggregator(listener);
296: ftpClient.setMessageListener(eventAggregator);
297: ftpClient.setProgressMonitor(eventAggregator);
298: ftpClient.setProgressMonitorEx(eventAggregator);
299: }
300:
301: /**
302: * Make a connection to the FTP server.
303: *
304: * @throws FTPException
305: * @throws IOException
306: */
307: public synchronized void connect() throws FTPException, IOException {
308: configureClient();
309: log.debug("Configured client");
310: ftpClient.connect();
311: log.debug("Client connected");
312: if (masterContext.isAutoLogin()) {
313: log.debug("Logging in");
314: ftpClient.login(masterContext.getUserName(), masterContext
315: .getPassword());
316: log.debug("Logged in");
317: configureTransferType(masterContext.getContentType());
318: } else {
319: log.debug("Manual login enabled");
320: }
321: }
322:
323: /**
324: * Perform a manual login using the credentials that have been set. This
325: * should only be performed if auto login is disabled - normally connect()
326: * performs the login automatically.
327: *
328: * @throws FTPException
329: * @throws IOException
330: */
331: public void manualLogin() throws FTPException, IOException {
332: checkConnection(true);
333: log.debug("Logging in");
334: ftpClient.login(masterContext.getUserName(), masterContext
335: .getPassword());
336: log.debug("Logged in");
337: configureTransferType(masterContext.getContentType());
338: }
339:
340: /**
341: * Apply the master context's settings to the client
342: *
343: * @throws IOException
344: * @throws FTPException
345: */
346: protected void configureClient() throws IOException, FTPException {
347: ftpClient.setRemoteHost(masterContext.getRemoteHost());
348: ftpClient.setRemotePort(masterContext.getRemotePort());
349: ftpClient.setTimeout(masterContext.getTimeout());
350: ftpClient
351: .setControlEncoding(masterContext.getControlEncoding());
352: ftpClient.setStrictReturnCodes(masterContext
353: .isStrictReturnCodes());
354: ftpClient.setDetectTransferMode(masterContext
355: .getDetectContentType());
356: ftpClient.setConnectMode(masterContext.getConnectMode());
357: ftpClient.setParserLocales(masterContext.getParserLocales());
358: ftpClient.setAutoPassiveIPSubstitution(masterContext
359: .isAutoPassiveIPSubstitution());
360: ftpClient.setDeleteOnFailure(masterContext.isDeleteOnFailure());
361: ftpClient
362: .setActiveIPAddress(masterContext.getActiveIPAddress());
363: ftpClient.setMonitorInterval(masterContext
364: .getTransferNotifyInterval());
365: ftpClient.setTransferBufferSize(masterContext
366: .getTransferBufferSize());
367: if (masterContext.getActiveHighPort() >= 0
368: && masterContext.getActiveLowPort() >= 0)
369: ftpClient.setActivePortRange(masterContext
370: .getActiveLowPort(), masterContext
371: .getActiveHighPort());
372: }
373:
374: protected void configureTransferType(FTPTransferType type)
375: throws IOException, FTPException {
376: ftpClient.setDetectTransferMode(masterContext
377: .getDetectContentType());
378: ftpClient.setType(type);
379: }
380:
381: protected void checkTransferSettings() throws FTPException {
382:
383: if (ftpClient.getDetectTransferMode() != masterContext
384: .getDetectContentType())
385: ftpClient.setDetectTransferMode(masterContext
386: .getDetectContentType());
387:
388: if (ftpClient.isStrictReturnCodes() != masterContext
389: .isStrictReturnCodes())
390: ftpClient.setStrictReturnCodes(masterContext
391: .isStrictReturnCodes());
392:
393: if (!ftpClient.getConnectMode().equals(
394: masterContext.getConnectMode()))
395: ftpClient.setConnectMode(masterContext.getConnectMode());
396:
397: if (ftpClient.isAutoPassiveIPSubstitution() != masterContext
398: .isAutoPassiveIPSubstitution())
399: ftpClient.setAutoPassiveIPSubstitution(masterContext
400: .isAutoPassiveIPSubstitution());
401:
402: if (ftpClient.isDeleteOnFailure() != masterContext
403: .isDeleteOnFailure())
404: ftpClient.setDeleteOnFailure(masterContext
405: .isDeleteOnFailure());
406:
407: if (ftpClient.getActiveIPAddress() != masterContext
408: .getActiveIPAddress())
409: ftpClient.setActiveIPAddress(masterContext
410: .getActiveIPAddress());
411:
412: if (ftpClient.getTransferBufferSize() != masterContext
413: .getTransferBufferSize())
414: ftpClient.setTransferBufferSize(masterContext
415: .getTransferBufferSize());
416:
417: if (ftpClient.getMonitorInterval() != masterContext
418: .getTransferNotifyInterval())
419: ftpClient.setMonitorInterval(masterContext
420: .getTransferNotifyInterval());
421:
422: if (masterContext.getActiveHighPort() != ftpClient
423: .getActiveHighPort()
424: || masterContext.getActiveLowPort() != ftpClient
425: .getActiveLowPort())
426: ftpClient.setActivePortRange(masterContext
427: .getActiveLowPort(), masterContext
428: .getActiveHighPort());
429: }
430:
431: protected void checkListingSettings() throws FTPException {
432: ftpClient.setParserLocales(masterContext.getParserLocales());
433: checkTransferSettings();
434: }
435:
436: /**
437: * Get statistics on file transfers and deletions.
438: *
439: * @return FTPStatistics
440: */
441: public synchronized FileStatistics getStatistics() {
442: return statistics;
443: }
444:
445: /**
446: * Request that the remote server execute the literal command supplied. In
447: * FTP, this is the equivalent of 'quote'. It could be used to send a SITE
448: * command to the server, e.g. "SITE recfm=FB lrecl=180 blksize=5400".
449: *
450: * @param command command string
451: * @return result string returned by server
452: * @throws FTPException
453: * @throws IOException
454: */
455: public synchronized String executeCommand(String command)
456: throws FTPException, IOException {
457: return ftpClient.quote(command);
458: }
459:
460: /**
461: * Cancel current transfer if underway
462: */
463: public void cancelAllTransfers() {
464:
465: log.debug("cancelAllTransfers() called");
466: ftpClient.cancelTransfer();
467: }
468:
469: /**
470: * Get a string that represents the remote system that the client is logged
471: * into.
472: *
473: * @return system string
474: * @throws FTPException
475: * @throws IOException
476: */
477: public synchronized String getSystemType() throws FTPException,
478: IOException {
479: return ftpClient.system();
480: }
481:
482: /**
483: * List the names of files and directories in the current directory on the FTP server.
484: *
485: * @return String[]
486: * @throws FTPException, IOException
487: */
488: public synchronized String[] directoryNameList()
489: throws FTPException, IOException {
490: return directoryNameList("", false);
491: }
492:
493: /**
494: * List the names of files and directories of a directory on the FTP server.
495: *
496: * @param directoryName name of the directory (generally not a path). Some
497: * servers will accept a wildcard.
498: * @param isLongListing true if the listing is a long format listing
499: * @return String[]
500: * @throws FTPException, IOException
501: */
502: public synchronized String[] directoryNameList(
503: String directoryName, boolean isLongListing)
504: throws FTPException, IOException {
505: checkListingSettings();
506: return ftpClient.dir(directoryName, isLongListing);
507: }
508:
509: /**
510: * List the current directory on the FTP server.
511: *
512: * @throws FTPException, IOException
513: * @throws ParseException
514: */
515: public synchronized FTPFile[] directoryList() throws FTPException,
516: IOException, ParseException {
517: return directoryList("");
518: }
519:
520: /**
521: * List a directory on the FTP server.
522: *
523: * @param directoryName name of the directory (generally not a path). Some
524: * servers will accept a wildcard.
525: * @throws FTPException, IOException
526: * @throws ParseException
527: */
528: public synchronized FTPFile[] directoryList(String directoryName)
529: throws FTPException, IOException, ParseException {
530: checkListingSettings();
531: return ftpClient.dirDetails(directoryName);
532: }
533:
534: /**
535: * Download a file from the FTP server into a byte array.
536: *
537: * @param remoteFileName name of the remote file to be downloaded
538: * @throws FTPException
539: */
540: public synchronized byte[] downloadByteArray(String remoteFileName)
541: throws FTPException, IOException {
542: checkTransferSettings();
543: return ftpClient.get(remoteFileName);
544: }
545:
546: /**
547: * Download a file from the FTP server .
548: *
549: * @param localFileName name (or full path) of the local file to be downloaded to
550: * @param remoteFileName name of the remote file to be downloaded
551: * @throws FTPException
552: */
553: public synchronized void downloadFile(String localFileName,
554: String remoteFileName) throws FTPException, IOException {
555: downloadFile(localFileName, remoteFileName, WriteMode.OVERWRITE);
556: }
557:
558: /**
559: * Download a file from the FTP server .
560: *
561: * @param localFileName name (or full path) of the local file to be downloaded to
562: * @param remoteFileName name of the remote file to be downloaded
563: * @param writeMode mode in which the file is written to the client machine
564: * @throws FTPException
565: */
566: public synchronized void downloadFile(String localFileName,
567: String remoteFileName, WriteMode writeMode)
568: throws FTPException, IOException {
569: checkTransferSettings();
570: if (writeMode.equals(WriteMode.RESUME)) {
571: ftpClient.resume();
572: } else if (writeMode.equals(WriteMode.APPEND)) {
573: throw new FTPException("Append not permitted for downloads");
574: }
575: ftpClient.get(localFileName, remoteFileName);
576: }
577:
578: /**
579: * Download a file from the FTP server as a stream. The close() method <b>must</b>
580: * be called on the stream once the stream has been read.
581: *
582: * @param remoteFileName name of the remote file to be downloaded
583: * @return InputStream
584: * @throws FTPException
585: */
586: public synchronized FileTransferInputStream downloadStream(
587: String remoteFileName) throws FTPException, IOException {
588: checkTransferSettings();
589: return new FTPInputStream(ftpClient, remoteFileName);
590: }
591:
592: /**
593: * Upload a file to the FTP server. If a null is supplied as
594: * the remoteFileName, the STOU (store unique) FTP feature will be used (if
595: * available) and the FTP server will generate a unique name for the file.
596: *
597: * @param localFileName
598: * name (or full path) of the local file to be downloaded to
599: * @param remoteFileName
600: * name of the remote file to be downloaded (or null to generate a unique name)
601: * @return name of remote file
602: * @throws FTPException
603: */
604: public synchronized String uploadFile(String localFileName,
605: String remoteFileName) throws FTPException, IOException {
606: return uploadFile(localFileName, remoteFileName,
607: WriteMode.OVERWRITE);
608: }
609:
610: /**
611: * Upload a file to the FTP server. If a null is supplied as
612: * the remoteFileName, the STOU (store unique) FTP feature will be used (if
613: * available) and the FTP server will generate a unique name for the file.
614: *
615: * @param localFileName
616: * name (or full path) of the local file to be downloaded to
617: * @param remoteFileName
618: * name of the remote file to be downloaded (or null to generate a unique name)
619: * @param writeMode mode to write to the remote file with
620: * @return name of remote file
621: * @throws FTPException
622: */
623: public synchronized String uploadFile(String localFileName,
624: String remoteFileName, WriteMode writeMode)
625: throws FTPException, IOException {
626: checkTransferSettings();
627: boolean append = false;
628: if (writeMode.equals(WriteMode.RESUME)) {
629: ftpClient.resume();
630: } else if (writeMode.equals(WriteMode.APPEND)) {
631: append = true;
632: }
633: return ftpClient.put(localFileName, remoteFileName, append);
634: }
635:
636: /**
637: * Upload a file to the FTP server by writing to a stream. The close() method <b>must</b>
638: * be called on the stream once the stream has been read.
639: * If a null is supplied as
640: * the remoteFileName, the STOU (store unique) FTP feature will be used (if
641: * available) and the FTP server will generate a unique name for the file. This
642: * name can be obtained afterwards from {@see FileTransferOutputStream#getRemoteFile()}
643: *
644: * @param remoteFileName name of the remote file to be uploaded
645: * @return FTPOutputStream
646: * @throws FTPException
647: * @throws IOException
648: */
649: public synchronized FileTransferOutputStream uploadStream(
650: String remoteFileName) throws FTPException, IOException {
651: return uploadStream(remoteFileName, WriteMode.OVERWRITE);
652: }
653:
654: /**
655: * Upload a file to the FTP server by writing to a stream. The close() method *must*
656: * be called on the stream once the stream has been read.
657: * If a null is supplied as
658: * the remoteFileName, the STOU (store unique) FTP feature will be used (if
659: * available) and the FTP server will generate a unique name for the file. This
660: * name can be obtained afterwards from {@see FileTransferOutputStream#getRemoteFile()}
661: *
662: * @param remoteFileName name of the remote file to be uploaded
663: * @param writeMode mode for writing to the server (supporting use of append)
664: * @return FTPOutputStream
665: * @throws FTPException
666: * @throws IOException
667: */
668: public synchronized FileTransferOutputStream uploadStream(
669: String remoteFileName, WriteMode writeMode)
670: throws FTPException, IOException {
671: checkTransferSettings();
672: if (WriteMode.RESUME.equals(writeMode))
673: throw new FTPException(
674: "Resume not supported for stream uploads");
675: boolean append = WriteMode.APPEND.equals(writeMode);
676: return new FTPOutputStream(ftpClient, remoteFileName, append);
677: }
678:
679: /**
680: * Get the size of a remote file.
681: *
682: * @param remoteFileName name of remote file
683: * @return long
684: * @throws FTPException
685: */
686: public synchronized long getSize(String remoteFileName)
687: throws FTPException, IOException {
688: return ftpClient.size(remoteFileName);
689: }
690:
691: /**
692: * Get the modified-time of a remote file.
693: *
694: * @param remoteFileName name of remote file
695: * @return Date
696: * @throws FTPException
697: */
698: public synchronized Date getModifiedTime(String remoteFileName)
699: throws FTPException, IOException {
700: return ftpClient.modtime(remoteFileName);
701: }
702:
703: /**
704: * Determine if a remote file exists.
705: *
706: * @param remoteFileName name of remote file
707: * @throws FTPException
708: */
709: public synchronized boolean exists(String remoteFileName)
710: throws FTPException, IOException {
711: return ftpClient.exists(remoteFileName);
712: }
713:
714: /**
715: * Deletes a remote file.
716: *
717: * @param remoteFileName name of remote file
718: * @throws FTPException
719: * @throws IOException
720: */
721: public synchronized void deleteFile(String remoteFileName)
722: throws FTPException, IOException {
723: ftpClient.delete(remoteFileName);
724: }
725:
726: /**
727: * Rename a remote file or directory.
728: *
729: * @param renameFromName
730: * original name
731: * @param renameToName
732: * new name
733: * @throws FTPException, IOException
734: */
735: public synchronized void rename(String renameFromName,
736: String renameToName) throws FTPException, IOException {
737: ftpClient.rename(renameFromName, renameToName);
738: }
739:
740: /**
741: * Change directory on the FTP server.
742: *
743: * @param directoryName
744: * name the remote directory to change into
745: * @throws FTPException, IOException
746: */
747: public synchronized void changeDirectory(String directoryName)
748: throws FTPException, IOException {
749: ftpClient.chdir(directoryName);
750: }
751:
752: /**
753: * Change to parent directory on the FTP server.
754: *
755: * @throws FTPException, IOException
756: */
757: public synchronized void changeToParentDirectory()
758: throws FTPException, IOException {
759: ftpClient.cdup();
760: }
761:
762: /**
763: * Get the current remote directory.
764: *
765: * @return current remote directory
766: * @throws FTPException
767: * @throws IOException
768: */
769: public synchronized String getRemoteDirectory() throws IOException,
770: FTPException {
771: return ftpClient.pwd();
772: }
773:
774: /**
775: * Create directory on the FTP server.
776: *
777: * @param directoryName
778: * name the remote directory to create
779: * @throws FTPException, IOException
780: */
781: public synchronized void createDirectory(String directoryName)
782: throws FTPException, IOException {
783: ftpClient.mkdir(directoryName);
784: }
785:
786: /**
787: * Create directory on the FTP server. The directory must be empty. Note
788: * that edtFTPj/PRO supports recursive directory deletions.
789: *
790: * @param directoryName
791: * name the remote directory to create
792: * @throws FTPException, IOException
793: */
794: public synchronized void deleteDirectory(String directoryName)
795: throws FTPException, IOException {
796: ftpClient.rmdir(directoryName);
797: }
798:
799: /**
800: * Disconnect from the FTP server.
801: *
802: * @throws FTPException, IOException
803: */
804: public synchronized void disconnect() throws FTPException,
805: IOException {
806: ftpClient.quit();
807: }
808:
809: /**
810: * Disconnect from the FTP server.
811: *
812: * @throws FTPException, IOException
813: */
814: public synchronized void disconnect(boolean immediate)
815: throws FTPException, IOException {
816: if (immediate)
817: ftpClient.quitImmediately();
818: else
819: ftpClient.quit();
820: }
821:
822: }
|