Source Code Cross Referenced for FTP.java in  » Build » ANT » org » apache » tools » ant » taskdefs » optional » net » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Build » ANT » org.apache.tools.ant.taskdefs.optional.net 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Licensed to the Apache Software Foundation (ASF) under one or more
0003:         *  contributor license agreements.  See the NOTICE file distributed with
0004:         *  this work for additional information regarding copyright ownership.
0005:         *  The ASF licenses this file to You under the Apache License, Version 2.0
0006:         *  (the "License"); you may not use this file except in compliance with
0007:         *  the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         *  Unless required by applicable law or agreed to in writing, software
0012:         *  distributed under the License is distributed on an "AS IS" BASIS,
0013:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         *  See the License for the specific language governing permissions and
0015:         *  limitations under the License.
0016:         *
0017:         */
0018:        package org.apache.tools.ant.taskdefs.optional.net;
0019:
0020:        import java.io.BufferedInputStream;
0021:        import java.io.BufferedOutputStream;
0022:        import java.io.BufferedWriter;
0023:        import java.io.File;
0024:        import java.io.FileInputStream;
0025:        import java.io.FileOutputStream;
0026:        import java.io.FileWriter;
0027:        import java.io.IOException;
0028:        import java.io.InputStream;
0029:        import java.io.OutputStream;
0030:        import java.text.SimpleDateFormat;
0031:        import java.util.Collection;
0032:        import java.util.Date;
0033:        import java.util.Enumeration;
0034:        import java.util.HashMap;
0035:        import java.util.HashSet;
0036:        import java.util.Hashtable;
0037:        import java.util.Iterator;
0038:        import java.util.Locale;
0039:        import java.util.Map;
0040:        import java.util.Set;
0041:        import java.util.StringTokenizer;
0042:        import java.util.Vector;
0043:
0044:        import org.apache.commons.net.ftp.FTPClient;
0045:        import org.apache.commons.net.ftp.FTPClientConfig;
0046:        import org.apache.commons.net.ftp.FTPFile;
0047:        import org.apache.commons.net.ftp.FTPReply;
0048:        import org.apache.tools.ant.BuildException;
0049:        import org.apache.tools.ant.DirectoryScanner;
0050:        import org.apache.tools.ant.Project;
0051:        import org.apache.tools.ant.Task;
0052:        import org.apache.tools.ant.taskdefs.Delete;
0053:        import org.apache.tools.ant.types.EnumeratedAttribute;
0054:        import org.apache.tools.ant.types.FileSet;
0055:        import org.apache.tools.ant.types.selectors.SelectorUtils;
0056:        import org.apache.tools.ant.util.FileUtils;
0057:        import org.apache.tools.ant.util.RetryHandler;
0058:        import org.apache.tools.ant.util.Retryable;
0059:
0060:        /**
0061:         * Basic FTP client. Performs the following actions:
0062:         * <ul>
0063:         *   <li> <strong>send</strong> - send files to a remote server. This is the
0064:         *   default action.</li>
0065:         *   <li> <strong>get</strong> - retrieve files from a remote server.</li>
0066:         *   <li> <strong>del</strong> - delete files from a remote server.</li>
0067:         *   <li> <strong>list</strong> - create a file listing.</li>
0068:         *   <li> <strong>chmod</strong> - change unix file permissions.</li>
0069:         *   <li> <strong>rmdir</strong> - remove directories, if empty, from a
0070:         *   remote server.</li>
0071:         * </ul>
0072:         * <strong>Note:</strong> Some FTP servers - notably the Solaris server - seem
0073:         * to hold data ports open after a "retr" operation, allowing them to timeout
0074:         * instead of shutting them down cleanly. This happens in active or passive
0075:         * mode, and the ports will remain open even after ending the FTP session. FTP
0076:         * "send" operations seem to close ports immediately. This behavior may cause
0077:         * problems on some systems when downloading large sets of files.
0078:         *
0079:         * @since Ant 1.3
0080:         */
0081:        public class FTP extends Task {
0082:            protected static final int SEND_FILES = 0;
0083:            protected static final int GET_FILES = 1;
0084:            protected static final int DEL_FILES = 2;
0085:            protected static final int LIST_FILES = 3;
0086:            protected static final int MK_DIR = 4;
0087:            protected static final int CHMOD = 5;
0088:            protected static final int RM_DIR = 6;
0089:            protected static final int SITE_CMD = 7;
0090:            /** return code of ftp - not implemented in commons-net version 1.0 */
0091:            private static final int CODE_521 = 521;
0092:
0093:            /** adjust uptodate calculations where server timestamps are HH:mm and client's
0094:             * are HH:mm:ss */
0095:            private static final long GRANULARITY_MINUTE = 60000L;
0096:
0097:            /** Default port for FTP */
0098:            public static final int DEFAULT_FTP_PORT = 21;
0099:
0100:            private static final FileUtils FILE_UTILS = FileUtils
0101:                    .getFileUtils();
0102:
0103:            private String remotedir;
0104:            private String server;
0105:            private String userid;
0106:            private String password;
0107:            private String account;
0108:            private File listing;
0109:            private boolean binary = true;
0110:            private boolean passive = false;
0111:            private boolean verbose = false;
0112:            private boolean newerOnly = false;
0113:            private long timeDiffMillis = 0;
0114:            private long granularityMillis = 0L;
0115:            private boolean timeDiffAuto = false;
0116:            private int action = SEND_FILES;
0117:            private Vector filesets = new Vector();
0118:            private Vector dirCache = new Vector();
0119:            private int transferred = 0;
0120:            private String remoteFileSep = "/";
0121:            private int port = DEFAULT_FTP_PORT;
0122:            private boolean skipFailedTransfers = false;
0123:            private int skipped = 0;
0124:            private boolean ignoreNoncriticalErrors = false;
0125:            private boolean preserveLastModified = false;
0126:            private String chmod = null;
0127:            private String umask = null;
0128:            private FTPSystemType systemTypeKey = FTPSystemType.getDefault();
0129:            private String defaultDateFormatConfig = null;
0130:            private String recentDateFormatConfig = null;
0131:            private LanguageCode serverLanguageCodeConfig = LanguageCode
0132:                    .getDefault();
0133:            private String serverTimeZoneConfig = null;
0134:            private String shortMonthNamesConfig = null;
0135:            private Granularity timestampGranularity = Granularity.getDefault();
0136:            private boolean isConfigurationSet = false;
0137:            private int retriesAllowed = 0;
0138:            private String siteCommand = null;
0139:            private String initialSiteCommand = null;
0140:
0141:            protected static final String[] ACTION_STRS = { "sending",
0142:                    "getting", "deleting", "listing", "making directory",
0143:                    "chmod", "removing", "site" };
0144:
0145:            protected static final String[] COMPLETED_ACTION_STRS = { "sent",
0146:                    "retrieved", "deleted", "listed", "created directory",
0147:                    "mode changed", "removed", "site command executed" };
0148:
0149:            protected static final String[] ACTION_TARGET_STRS = { "files",
0150:                    "files", "files", "files", "directory", "files",
0151:                    "directories", "site command" };
0152:
0153:            /**
0154:             * internal class allowing to read the contents of a remote file system
0155:             * using the FTP protocol
0156:             * used in particular for ftp get operations
0157:             * differences with DirectoryScanner
0158:             * "" (the root of the fileset) is never included in the included directories
0159:             * followSymlinks defaults to false
0160:             */
0161:            protected class FTPDirectoryScanner extends DirectoryScanner {
0162:                // CheckStyle:VisibilityModifier OFF - bc
0163:                protected FTPClient ftp = null;
0164:                // CheckStyle:VisibilityModifier ON
0165:
0166:                private String rootPath = null;
0167:
0168:                /**
0169:                 * since ant 1.6
0170:                 * this flag should be set to true on UNIX and can save scanning time
0171:                 */
0172:                private boolean remoteSystemCaseSensitive = false;
0173:                private boolean remoteSensitivityChecked = false;
0174:
0175:                /**
0176:                 * constructor
0177:                 * @param ftp  ftpclient object
0178:                 */
0179:                public FTPDirectoryScanner(FTPClient ftp) {
0180:                    super ();
0181:                    this .ftp = ftp;
0182:                    this .setFollowSymlinks(false);
0183:                }
0184:
0185:                /**
0186:                 * scans the remote directory,
0187:                 * storing internally the included files, directories, ...
0188:                 */
0189:                public void scan() {
0190:                    if (includes == null) {
0191:                        // No includes supplied, so set it to 'matches all'
0192:                        includes = new String[1];
0193:                        includes[0] = "**";
0194:                    }
0195:                    if (excludes == null) {
0196:                        excludes = new String[0];
0197:                    }
0198:
0199:                    filesIncluded = new Vector();
0200:                    filesNotIncluded = new Vector();
0201:                    filesExcluded = new Vector();
0202:                    dirsIncluded = new Vector();
0203:                    dirsNotIncluded = new Vector();
0204:                    dirsExcluded = new Vector();
0205:
0206:                    try {
0207:                        String cwd = ftp.printWorkingDirectory();
0208:                        // always start from the current ftp working dir
0209:                        forceRemoteSensitivityCheck();
0210:
0211:                        checkIncludePatterns();
0212:                        clearCaches();
0213:                        ftp.changeWorkingDirectory(cwd);
0214:                    } catch (IOException e) {
0215:                        throw new BuildException("Unable to scan FTP server: ",
0216:                                e);
0217:                    }
0218:                }
0219:
0220:                /**
0221:                 * this routine is actually checking all the include patterns in
0222:                 * order to avoid scanning everything under base dir
0223:                 * @since ant1.6
0224:                 */
0225:                private void checkIncludePatterns() {
0226:
0227:                    Hashtable newroots = new Hashtable();
0228:                    // put in the newroots vector the include patterns without
0229:                    // wildcard tokens
0230:                    for (int icounter = 0; icounter < includes.length; icounter++) {
0231:                        String newpattern = SelectorUtils
0232:                                .rtrimWildcardTokens(includes[icounter]);
0233:                        newroots.put(newpattern, includes[icounter]);
0234:                    }
0235:                    if (remotedir == null) {
0236:                        try {
0237:                            remotedir = ftp.printWorkingDirectory();
0238:                        } catch (IOException e) {
0239:                            throw new BuildException(
0240:                                    "could not read current ftp directory",
0241:                                    getLocation());
0242:                        }
0243:                    }
0244:                    AntFTPFile baseFTPFile = new AntFTPRootFile(ftp, remotedir);
0245:                    rootPath = baseFTPFile.getAbsolutePath();
0246:                    // construct it
0247:                    if (newroots.containsKey("")) {
0248:                        // we are going to scan everything anyway
0249:                        scandir(rootPath, "", true);
0250:                    } else {
0251:                        // only scan directories that can include matched files or
0252:                        // directories
0253:                        Enumeration enum2 = newroots.keys();
0254:
0255:                        while (enum2.hasMoreElements()) {
0256:                            String currentelement = (String) enum2
0257:                                    .nextElement();
0258:                            String originalpattern = (String) newroots
0259:                                    .get(currentelement);
0260:                            AntFTPFile myfile = new AntFTPFile(baseFTPFile,
0261:                                    currentelement);
0262:                            boolean isOK = true;
0263:                            boolean traversesSymlinks = false;
0264:                            String path = null;
0265:
0266:                            if (myfile.exists()) {
0267:                                forceRemoteSensitivityCheck();
0268:                                if (remoteSensitivityChecked
0269:                                        && remoteSystemCaseSensitive
0270:                                        && isFollowSymlinks()) {
0271:                                    // cool case,
0272:                                    //we do not need to scan all the subdirs in the relative path
0273:                                    path = myfile.getFastRelativePath();
0274:                                } else {
0275:                                    // may be on a case insensitive file system.  We want
0276:                                    // the results to show what's really on the disk, so
0277:                                    // we need to double check.
0278:                                    try {
0279:                                        path = myfile.getRelativePath();
0280:                                        traversesSymlinks = myfile
0281:                                                .isTraverseSymlinks();
0282:                                    } catch (IOException be) {
0283:                                        throw new BuildException(be,
0284:                                                getLocation());
0285:                                    } catch (BuildException be) {
0286:                                        isOK = false;
0287:                                    }
0288:                                }
0289:                            } else {
0290:                                isOK = false;
0291:                            }
0292:                            if (isOK) {
0293:                                currentelement = path.replace(remoteFileSep
0294:                                        .charAt(0), File.separatorChar);
0295:                                if (!isFollowSymlinks() && traversesSymlinks) {
0296:                                    continue;
0297:                                }
0298:
0299:                                if (myfile.isDirectory()) {
0300:                                    if (isIncluded(currentelement)
0301:                                            && currentelement.length() > 0) {
0302:                                        accountForIncludedDir(currentelement,
0303:                                                myfile, true);
0304:                                    } else {
0305:                                        if (currentelement.length() > 0) {
0306:                                            if (currentelement
0307:                                                    .charAt(currentelement
0308:                                                            .length() - 1) != File.separatorChar) {
0309:                                                currentelement = currentelement
0310:                                                        + File.separatorChar;
0311:                                            }
0312:                                        }
0313:                                        scandir(myfile.getAbsolutePath(),
0314:                                                currentelement, true);
0315:                                    }
0316:                                } else {
0317:                                    if (isCaseSensitive
0318:                                            && originalpattern
0319:                                                    .equals(currentelement)) {
0320:                                        accountForIncludedFile(currentelement);
0321:                                    } else if (!isCaseSensitive
0322:                                            && originalpattern
0323:                                                    .equalsIgnoreCase(currentelement)) {
0324:                                        accountForIncludedFile(currentelement);
0325:                                    }
0326:                                }
0327:                            }
0328:                        }
0329:                    }
0330:                }
0331:
0332:                /**
0333:                 * scans a particular directory
0334:                 * @param dir directory to scan
0335:                 * @param vpath  relative path to the base directory of the remote fileset
0336:                 * always ended with a File.separator
0337:                 * @param fast seems to be always true in practice
0338:                 */
0339:                protected void scandir(String dir, String vpath, boolean fast) {
0340:                    // avoid double scanning of directories, can only happen in fast mode
0341:                    if (fast && hasBeenScanned(vpath)) {
0342:                        return;
0343:                    }
0344:                    try {
0345:                        if (!ftp.changeWorkingDirectory(dir)) {
0346:                            return;
0347:                        }
0348:                        String completePath = null;
0349:                        if (!vpath.equals("")) {
0350:                            completePath = rootPath
0351:                                    + remoteFileSep
0352:                                    + vpath.replace(File.separatorChar,
0353:                                            remoteFileSep.charAt(0));
0354:                        } else {
0355:                            completePath = rootPath;
0356:                        }
0357:                        FTPFile[] newfiles = listFiles(completePath, false);
0358:
0359:                        if (newfiles == null) {
0360:                            ftp.changeToParentDirectory();
0361:                            return;
0362:                        }
0363:                        for (int i = 0; i < newfiles.length; i++) {
0364:                            FTPFile file = newfiles[i];
0365:                            if (!file.getName().equals(".")
0366:                                    && !file.getName().equals("..")) {
0367:                                if (isFunctioningAsDirectory(ftp, dir, file)) {
0368:                                    String name = vpath + file.getName();
0369:                                    boolean slowScanAllowed = true;
0370:                                    if (!isFollowSymlinks()
0371:                                            && file.isSymbolicLink()) {
0372:                                        dirsExcluded.addElement(name);
0373:                                        slowScanAllowed = false;
0374:                                    } else if (isIncluded(name)) {
0375:                                        accountForIncludedDir(name,
0376:                                                new AntFTPFile(ftp, file,
0377:                                                        completePath), fast);
0378:                                    } else {
0379:                                        dirsNotIncluded.addElement(name);
0380:                                        if (fast && couldHoldIncluded(name)) {
0381:                                            scandir(file.getName(), name
0382:                                                    + File.separator, fast);
0383:                                        }
0384:                                    }
0385:                                    if (!fast && slowScanAllowed) {
0386:                                        scandir(file.getName(), name
0387:                                                + File.separator, fast);
0388:                                    }
0389:                                } else {
0390:                                    String name = vpath + file.getName();
0391:                                    if (!isFollowSymlinks()
0392:                                            && file.isSymbolicLink()) {
0393:                                        filesExcluded.addElement(name);
0394:                                    } else if (isFunctioningAsFile(ftp, dir,
0395:                                            file)) {
0396:                                        accountForIncludedFile(name);
0397:                                    }
0398:                                }
0399:                            }
0400:                        }
0401:                        ftp.changeToParentDirectory();
0402:                    } catch (IOException e) {
0403:                        throw new BuildException(
0404:                                "Error while communicating with FTP "
0405:                                        + "server: ", e);
0406:                    }
0407:                }
0408:
0409:                /**
0410:                 * process included file
0411:                 * @param name  path of the file relative to the directory of the fileset
0412:                 */
0413:                private void accountForIncludedFile(String name) {
0414:                    if (!filesIncluded.contains(name)
0415:                            && !filesExcluded.contains(name)) {
0416:
0417:                        if (isIncluded(name)) {
0418:                            if (!isExcluded(name)) {
0419:                                filesIncluded.addElement(name);
0420:                            } else {
0421:                                filesExcluded.addElement(name);
0422:                            }
0423:                        } else {
0424:                            filesNotIncluded.addElement(name);
0425:                        }
0426:                    }
0427:                }
0428:
0429:                /**
0430:                 *
0431:                 * @param name path of the directory relative to the directory of
0432:                 * the fileset
0433:                 * @param file directory as file
0434:                 * @param fast
0435:                 */
0436:                private void accountForIncludedDir(String name,
0437:                        AntFTPFile file, boolean fast) {
0438:                    if (!dirsIncluded.contains(name)
0439:                            && !dirsExcluded.contains(name)) {
0440:
0441:                        if (!isExcluded(name)) {
0442:                            if (fast) {
0443:                                if (file.isSymbolicLink()) {
0444:                                    try {
0445:                                        file.getClient()
0446:                                                .changeWorkingDirectory(
0447:                                                        file.curpwd);
0448:                                    } catch (IOException ioe) {
0449:                                        throw new BuildException(
0450:                                                "could not change directory to curpwd");
0451:                                    }
0452:                                    scandir(file.getLink(), name
0453:                                            + File.separator, fast);
0454:                                } else {
0455:                                    try {
0456:                                        file.getClient()
0457:                                                .changeWorkingDirectory(
0458:                                                        file.curpwd);
0459:                                    } catch (IOException ioe) {
0460:                                        throw new BuildException(
0461:                                                "could not change directory to curpwd");
0462:                                    }
0463:                                    scandir(file.getName(), name
0464:                                            + File.separator, fast);
0465:                                }
0466:                            }
0467:                            dirsIncluded.addElement(name);
0468:                        } else {
0469:                            dirsExcluded.addElement(name);
0470:                            if (fast && couldHoldIncluded(name)) {
0471:                                try {
0472:                                    file.getClient().changeWorkingDirectory(
0473:                                            file.curpwd);
0474:                                } catch (IOException ioe) {
0475:                                    throw new BuildException(
0476:                                            "could not change directory to curpwd");
0477:                                }
0478:                                scandir(file.getName(), name + File.separator,
0479:                                        fast);
0480:                            }
0481:                        }
0482:                    }
0483:                }
0484:
0485:                /**
0486:                 * temporary table to speed up the various scanning methods below
0487:                 *
0488:                 * @since Ant 1.6
0489:                 */
0490:                private Map fileListMap = new HashMap();
0491:                /**
0492:                 * List of all scanned directories.
0493:                 *
0494:                 * @since Ant 1.6
0495:                 */
0496:                private Set scannedDirs = new HashSet();
0497:
0498:                /**
0499:                 * Has the directory with the given path relative to the base
0500:                 * directory already been scanned?
0501:                 *
0502:                 * <p>Registers the given directory as scanned as a side effect.</p>
0503:                 *
0504:                 * @since Ant 1.6
0505:                 */
0506:                private boolean hasBeenScanned(String vpath) {
0507:                    return !scannedDirs.add(vpath);
0508:                }
0509:
0510:                /**
0511:                 * Clear internal caches.
0512:                 *
0513:                 * @since Ant 1.6
0514:                 */
0515:                private void clearCaches() {
0516:                    fileListMap.clear();
0517:                    scannedDirs.clear();
0518:                }
0519:
0520:                /**
0521:                 * list the files present in one directory.
0522:                 * @param directory full path on the remote side
0523:                 * @param changedir if true change to directory directory before listing
0524:                 * @return array of FTPFile
0525:                 */
0526:                public FTPFile[] listFiles(String directory, boolean changedir) {
0527:                    //getProject().log("listing files in directory " + directory, Project.MSG_DEBUG);
0528:                    String currentPath = directory;
0529:                    if (changedir) {
0530:                        try {
0531:                            boolean result = ftp
0532:                                    .changeWorkingDirectory(directory);
0533:                            if (!result) {
0534:                                return null;
0535:                            }
0536:                            currentPath = ftp.printWorkingDirectory();
0537:                        } catch (IOException ioe) {
0538:                            throw new BuildException(ioe, getLocation());
0539:                        }
0540:                    }
0541:                    if (fileListMap.containsKey(currentPath)) {
0542:                        getProject().log("filelist map used in listing files",
0543:                                Project.MSG_DEBUG);
0544:                        return ((FTPFile[]) fileListMap.get(currentPath));
0545:                    }
0546:                    FTPFile[] result = null;
0547:                    try {
0548:                        result = ftp.listFiles();
0549:                    } catch (IOException ioe) {
0550:                        throw new BuildException(ioe, getLocation());
0551:                    }
0552:                    fileListMap.put(currentPath, result);
0553:                    if (!remoteSensitivityChecked) {
0554:                        checkRemoteSensitivity(result, directory);
0555:                    }
0556:                    return result;
0557:                }
0558:
0559:                private void forceRemoteSensitivityCheck() {
0560:                    if (!remoteSensitivityChecked) {
0561:                        try {
0562:                            checkRemoteSensitivity(ftp.listFiles(), ftp
0563:                                    .printWorkingDirectory());
0564:                        } catch (IOException ioe) {
0565:                            throw new BuildException(ioe, getLocation());
0566:                        }
0567:                    }
0568:                }
0569:
0570:                /**
0571:                 * cd into one directory and
0572:                 * list the files present in one directory.
0573:                 * @param directory full path on the remote side
0574:                 * @return array of FTPFile
0575:                 */
0576:                public FTPFile[] listFiles(String directory) {
0577:                    return listFiles(directory, true);
0578:                }
0579:
0580:                private void checkRemoteSensitivity(FTPFile[] array,
0581:                        String directory) {
0582:                    if (array == null) {
0583:                        return;
0584:                    }
0585:                    boolean candidateFound = false;
0586:                    String target = null;
0587:                    for (int icounter = 0; icounter < array.length; icounter++) {
0588:                        if (array[icounter].isDirectory()) {
0589:                            if (!array[icounter].getName().equals(".")
0590:                                    && !array[icounter].getName().equals("..")) {
0591:                                candidateFound = true;
0592:                                target = fiddleName(array[icounter].getName());
0593:                                getProject().log(
0594:                                        "will try to cd to " + target
0595:                                                + " where a directory called "
0596:                                                + array[icounter].getName()
0597:                                                + " exists", Project.MSG_DEBUG);
0598:                                for (int pcounter = 0; pcounter < array.length; pcounter++) {
0599:                                    if (array[pcounter].getName()
0600:                                            .equals(target)
0601:                                            && pcounter != icounter) {
0602:                                        candidateFound = false;
0603:                                    }
0604:                                }
0605:                                if (candidateFound) {
0606:                                    break;
0607:                                }
0608:                            }
0609:                        }
0610:                    }
0611:                    if (candidateFound) {
0612:                        try {
0613:                            getProject().log(
0614:                                    "testing case sensitivity, attempting to cd to "
0615:                                            + target, Project.MSG_DEBUG);
0616:                            remoteSystemCaseSensitive = !ftp
0617:                                    .changeWorkingDirectory(target);
0618:                        } catch (IOException ioe) {
0619:                            remoteSystemCaseSensitive = true;
0620:                        } finally {
0621:                            try {
0622:                                ftp.changeWorkingDirectory(directory);
0623:                            } catch (IOException ioe) {
0624:                                throw new BuildException(ioe, getLocation());
0625:                            }
0626:                        }
0627:                        getProject().log(
0628:                                "remote system is case sensitive : "
0629:                                        + remoteSystemCaseSensitive,
0630:                                Project.MSG_VERBOSE);
0631:                        remoteSensitivityChecked = true;
0632:                    }
0633:                }
0634:
0635:                private String fiddleName(String origin) {
0636:                    StringBuffer result = new StringBuffer();
0637:                    for (int icounter = 0; icounter < origin.length(); icounter++) {
0638:                        if (Character.isLowerCase(origin.charAt(icounter))) {
0639:                            result.append(Character.toUpperCase(origin
0640:                                    .charAt(icounter)));
0641:                        } else if (Character.isUpperCase(origin
0642:                                .charAt(icounter))) {
0643:                            result.append(Character.toLowerCase(origin
0644:                                    .charAt(icounter)));
0645:                        } else {
0646:                            result.append(origin.charAt(icounter));
0647:                        }
0648:                    }
0649:                    return result.toString();
0650:                }
0651:
0652:                /**
0653:                 * an AntFTPFile is a representation of a remote file
0654:                 * @since Ant 1.6
0655:                 */
0656:                protected class AntFTPFile {
0657:                    /**
0658:                     * ftp client
0659:                     */
0660:                    private FTPClient client;
0661:                    /**
0662:                     * parent directory of the file
0663:                     */
0664:                    private String curpwd;
0665:                    /**
0666:                     * the file itself
0667:                     */
0668:                    private FTPFile ftpFile;
0669:                    /**
0670:                     *
0671:                     */
0672:                    private AntFTPFile parent = null;
0673:                    private boolean relativePathCalculated = false;
0674:                    private boolean traversesSymlinks = false;
0675:                    private String relativePath = "";
0676:
0677:                    /**
0678:                     * constructor
0679:                     * @param client ftp client variable
0680:                     * @param ftpFile the file
0681:                     * @param curpwd absolute remote path where the file is found
0682:                     */
0683:                    public AntFTPFile(FTPClient client, FTPFile ftpFile,
0684:                            String curpwd) {
0685:                        this .client = client;
0686:                        this .ftpFile = ftpFile;
0687:                        this .curpwd = curpwd;
0688:                    }
0689:
0690:                    /**
0691:                     * other constructor
0692:                     * @param parent the parent file
0693:                     * @param path  a relative path to the parent file
0694:                     */
0695:                    public AntFTPFile(AntFTPFile parent, String path) {
0696:                        this .parent = parent;
0697:                        this .client = parent.client;
0698:                        Vector pathElements = SelectorUtils.tokenizePath(path);
0699:                        try {
0700:                            boolean result = this .client
0701:                                    .changeWorkingDirectory(parent
0702:                                            .getAbsolutePath());
0703:                            //this should not happen, except if parent has been deleted by another process
0704:                            if (!result) {
0705:                                return;
0706:                            }
0707:                            this .curpwd = parent.getAbsolutePath();
0708:                        } catch (IOException ioe) {
0709:                            throw new BuildException(
0710:                                    "could not change working dir to "
0711:                                            + parent.curpwd);
0712:                        }
0713:                        for (int fcount = 0; fcount < pathElements.size() - 1; fcount++) {
0714:                            String currentPathElement = (String) pathElements
0715:                                    .elementAt(fcount);
0716:                            try {
0717:                                boolean result = this .client
0718:                                        .changeWorkingDirectory(currentPathElement);
0719:                                if (!result
0720:                                        && !isCaseSensitive()
0721:                                        && (remoteSystemCaseSensitive || !remoteSensitivityChecked)) {
0722:                                    currentPathElement = findPathElementCaseUnsensitive(
0723:                                            this .curpwd, currentPathElement);
0724:                                    if (currentPathElement == null) {
0725:                                        return;
0726:                                    }
0727:                                } else if (!result) {
0728:                                    return;
0729:                                }
0730:                                this .curpwd = this .curpwd + remoteFileSep
0731:                                        + currentPathElement;
0732:                            } catch (IOException ioe) {
0733:                                throw new BuildException(
0734:                                        "could not change working dir to "
0735:                                                + (String) pathElements
0736:                                                        .elementAt(fcount)
0737:                                                + " from " + this .curpwd);
0738:                            }
0739:
0740:                        }
0741:                        String lastpathelement = (String) pathElements
0742:                                .elementAt(pathElements.size() - 1);
0743:                        FTPFile[] theFiles = listFiles(this .curpwd);
0744:                        this .ftpFile = getFile(theFiles, lastpathelement);
0745:                    }
0746:
0747:                    /**
0748:                     * find a file in a directory in case unsensitive way
0749:                     * @param parentPath        where we are
0750:                     * @param soughtPathElement what is being sought
0751:                     * @return                  the first file found or null if not found
0752:                     */
0753:                    private String findPathElementCaseUnsensitive(
0754:                            String parentPath, String soughtPathElement) {
0755:                        // we are already in the right path, so the second parameter
0756:                        // is false
0757:                        FTPFile[] theFiles = listFiles(parentPath, false);
0758:                        if (theFiles == null) {
0759:                            return null;
0760:                        }
0761:                        for (int icounter = 0; icounter < theFiles.length; icounter++) {
0762:                            if (theFiles[icounter].getName().equalsIgnoreCase(
0763:                                    soughtPathElement)) {
0764:                                return theFiles[icounter].getName();
0765:                            }
0766:                        }
0767:                        return null;
0768:                    }
0769:
0770:                    /**
0771:                     * find out if the file exists
0772:                     * @return  true if the file exists
0773:                     */
0774:                    public boolean exists() {
0775:                        return (ftpFile != null);
0776:                    }
0777:
0778:                    /**
0779:                     * if the file is a symbolic link, find out to what it is pointing
0780:                     * @return the target of the symbolic link
0781:                     */
0782:                    public String getLink() {
0783:                        return ftpFile.getLink();
0784:                    }
0785:
0786:                    /**
0787:                     * get the name of the file
0788:                     * @return the name of the file
0789:                     */
0790:                    public String getName() {
0791:                        return ftpFile.getName();
0792:                    }
0793:
0794:                    /**
0795:                     * find out the absolute path of the file
0796:                     * @return absolute path as string
0797:                     */
0798:                    public String getAbsolutePath() {
0799:                        return curpwd + remoteFileSep + ftpFile.getName();
0800:                    }
0801:
0802:                    /**
0803:                     * find out the relative path assuming that the path used to construct
0804:                     * this AntFTPFile was spelled properly with regards to case.
0805:                     * This is OK on a case sensitive system such as UNIX
0806:                     * @return relative path
0807:                     */
0808:                    public String getFastRelativePath() {
0809:                        String absPath = getAbsolutePath();
0810:                        if (absPath.indexOf(rootPath + remoteFileSep) == 0) {
0811:                            return absPath.substring(rootPath.length()
0812:                                    + remoteFileSep.length());
0813:                        }
0814:                        return null;
0815:                    }
0816:
0817:                    /**
0818:                     * find out the relative path to the rootPath of the enclosing scanner.
0819:                     * this relative path is spelled exactly like on disk,
0820:                     * for instance if the AntFTPFile has been instantiated as ALPHA,
0821:                     * but the file is really called alpha, this method will return alpha.
0822:                     * If a symbolic link is encountered, it is followed, but the name of the link
0823:                     * rather than the name of the target is returned.
0824:                     * (ie does not behave like File.getCanonicalPath())
0825:                     * @return                relative path, separated by remoteFileSep
0826:                     * @throws IOException    if a change directory fails, ...
0827:                     * @throws BuildException if one of the components of the relative path cannot
0828:                     * be found.
0829:                     */
0830:                    public String getRelativePath() throws IOException,
0831:                            BuildException {
0832:                        if (!relativePathCalculated) {
0833:                            if (parent != null) {
0834:                                traversesSymlinks = parent.isTraverseSymlinks();
0835:                                relativePath = getRelativePath(parent
0836:                                        .getAbsolutePath(), parent
0837:                                        .getRelativePath());
0838:                            } else {
0839:                                relativePath = getRelativePath(rootPath, "");
0840:                                relativePathCalculated = true;
0841:                            }
0842:                        }
0843:                        return relativePath;
0844:                    }
0845:
0846:                    /**
0847:                     * get thge relative path of this file
0848:                     * @param currentPath          base path
0849:                     * @param currentRelativePath  relative path of the base path with regards to remote dir
0850:                     * @return relative path
0851:                     */
0852:                    private String getRelativePath(String currentPath,
0853:                            String currentRelativePath) {
0854:                        Vector pathElements = SelectorUtils.tokenizePath(
0855:                                getAbsolutePath(), remoteFileSep);
0856:                        Vector pathElements2 = SelectorUtils.tokenizePath(
0857:                                currentPath, remoteFileSep);
0858:                        String relPath = currentRelativePath;
0859:                        for (int pcount = pathElements2.size(); pcount < pathElements
0860:                                .size(); pcount++) {
0861:                            String currentElement = (String) pathElements
0862:                                    .elementAt(pcount);
0863:                            FTPFile[] theFiles = listFiles(currentPath);
0864:                            FTPFile theFile = null;
0865:                            if (theFiles != null) {
0866:                                theFile = getFile(theFiles, currentElement);
0867:                            }
0868:                            if (!relPath.equals("")) {
0869:                                relPath = relPath + remoteFileSep;
0870:                            }
0871:                            if (theFile == null) {
0872:                                // hit a hidden file assume not a symlink
0873:                                relPath = relPath + currentElement;
0874:                                currentPath = currentPath + remoteFileSep
0875:                                        + currentElement;
0876:                                log("Hidden file " + relPath
0877:                                        + " assumed to not be a symlink.",
0878:                                        Project.MSG_VERBOSE);
0879:                            } else {
0880:                                traversesSymlinks = traversesSymlinks
0881:                                        || theFile.isSymbolicLink();
0882:                                relPath = relPath + theFile.getName();
0883:                                currentPath = currentPath + remoteFileSep
0884:                                        + theFile.getName();
0885:                            }
0886:                        }
0887:                        return relPath;
0888:                    }
0889:
0890:                    /**
0891:                     * find a file matching a string in an array of FTPFile.
0892:                     * This method will find "alpha" when requested for "ALPHA"
0893:                     * if and only if the caseSensitive attribute is set to false.
0894:                     * When caseSensitive is set to true, only the exact match is returned.
0895:                     * @param theFiles  array of files
0896:                     * @param lastpathelement  the file name being sought
0897:                     * @return null if the file cannot be found, otherwise return the matching file.
0898:                     */
0899:                    public FTPFile getFile(FTPFile[] theFiles,
0900:                            String lastpathelement) {
0901:                        if (theFiles == null) {
0902:                            return null;
0903:                        }
0904:                        for (int fcount = 0; fcount < theFiles.length; fcount++) {
0905:                            if (theFiles[fcount].getName().equals(
0906:                                    lastpathelement)) {
0907:                                return theFiles[fcount];
0908:                            } else if (!isCaseSensitive()
0909:                                    && theFiles[fcount].getName()
0910:                                            .equalsIgnoreCase(lastpathelement)) {
0911:                                return theFiles[fcount];
0912:                            }
0913:                        }
0914:                        return null;
0915:                    }
0916:
0917:                    /**
0918:                     * tell if a file is a directory.
0919:                     * note that it will return false for symbolic links pointing to directories.
0920:                     * @return <code>true</code> for directories
0921:                     */
0922:                    public boolean isDirectory() {
0923:                        return ftpFile.isDirectory();
0924:                    }
0925:
0926:                    /**
0927:                     * tell if a file is a symbolic link
0928:                     * @return <code>true</code> for symbolic links
0929:                     */
0930:                    public boolean isSymbolicLink() {
0931:                        return ftpFile.isSymbolicLink();
0932:                    }
0933:
0934:                    /**
0935:                     * return the attached FTP client object.
0936:                     * Warning : this instance is really shared with the enclosing class.
0937:                     * @return  FTP client
0938:                     */
0939:                    protected FTPClient getClient() {
0940:                        return client;
0941:                    }
0942:
0943:                    /**
0944:                     * sets the current path of an AntFTPFile
0945:                     * @param curpwd the current path one wants to set
0946:                     */
0947:                    protected void setCurpwd(String curpwd) {
0948:                        this .curpwd = curpwd;
0949:                    }
0950:
0951:                    /**
0952:                     * returns the path of the directory containing the AntFTPFile.
0953:                     * of the full path of the file itself in case of AntFTPRootFile
0954:                     * @return parent directory of the AntFTPFile
0955:                     */
0956:                    public String getCurpwd() {
0957:                        return curpwd;
0958:                    }
0959:
0960:                    /**
0961:                     * find out if a symbolic link is encountered in the relative path of this file
0962:                     * from rootPath.
0963:                     * @return <code>true</code> if a symbolic link is encountered in the relative path.
0964:                     * @throws IOException if one of the change directory or directory listing operations
0965:                     * fails
0966:                     * @throws BuildException if a path component in the relative path cannot be found.
0967:                     */
0968:                    public boolean isTraverseSymlinks() throws IOException,
0969:                            BuildException {
0970:                        if (!relativePathCalculated) {
0971:                            // getRelativePath also finds about symlinks
0972:                            getRelativePath();
0973:                        }
0974:                        return traversesSymlinks;
0975:                    }
0976:
0977:                    /**
0978:                     * Get a string rep of this object.
0979:                     * @return a string containing the pwd and the file.
0980:                     */
0981:                    public String toString() {
0982:                        return "AntFtpFile: " + curpwd + "%" + ftpFile;
0983:                    }
0984:                }
0985:
0986:                /**
0987:                 * special class to represent the remote directory itself
0988:                 * @since Ant 1.6
0989:                 */
0990:                protected class AntFTPRootFile extends AntFTPFile {
0991:                    private String remotedir;
0992:
0993:                    /**
0994:                     * constructor
0995:                     * @param aclient FTP client
0996:                     * @param remotedir remote directory
0997:                     */
0998:                    public AntFTPRootFile(FTPClient aclient, String remotedir) {
0999:                        super (aclient, null, remotedir);
1000:                        this .remotedir = remotedir;
1001:                        try {
1002:                            this .getClient().changeWorkingDirectory(
1003:                                    this .remotedir);
1004:                            this .setCurpwd(this .getClient()
1005:                                    .printWorkingDirectory());
1006:                        } catch (IOException ioe) {
1007:                            throw new BuildException(ioe, getLocation());
1008:                        }
1009:                    }
1010:
1011:                    /**
1012:                     * find the absolute path
1013:                     * @return absolute path
1014:                     */
1015:                    public String getAbsolutePath() {
1016:                        return this .getCurpwd();
1017:                    }
1018:
1019:                    /**
1020:                     * find out the relative path to root
1021:                     * @return empty string
1022:                     * @throws BuildException actually never
1023:                     * @throws IOException  actually never
1024:                     */
1025:                    public String getRelativePath() throws BuildException,
1026:                            IOException {
1027:                        return "";
1028:                    }
1029:                }
1030:            }
1031:
1032:            /**
1033:             * check FTPFiles to check whether they function as directories too
1034:             * the FTPFile API seem to make directory and symbolic links incompatible
1035:             * we want to find out if we can cd to a symbolic link
1036:             * @param dir  the parent directory of the file to test
1037:             * @param file the file to test
1038:             * @return true if it is possible to cd to this directory
1039:             * @since ant 1.6
1040:             */
1041:            private boolean isFunctioningAsDirectory(FTPClient ftp, String dir,
1042:                    FTPFile file) {
1043:                boolean result = false;
1044:                String currentWorkingDir = null;
1045:                if (file.isDirectory()) {
1046:                    return true;
1047:                } else if (file.isFile()) {
1048:                    return false;
1049:                }
1050:                try {
1051:                    currentWorkingDir = ftp.printWorkingDirectory();
1052:                } catch (IOException ioe) {
1053:                    getProject().log(
1054:                            "could not find current working directory " + dir
1055:                                    + " while checking a symlink",
1056:                            Project.MSG_DEBUG);
1057:                }
1058:                if (currentWorkingDir != null) {
1059:                    try {
1060:                        result = ftp.changeWorkingDirectory(file.getLink());
1061:                    } catch (IOException ioe) {
1062:                        getProject().log(
1063:                                "could not cd to " + file.getLink()
1064:                                        + " while checking a symlink",
1065:                                Project.MSG_DEBUG);
1066:                    }
1067:                    if (result) {
1068:                        boolean comeback = false;
1069:                        try {
1070:                            comeback = ftp
1071:                                    .changeWorkingDirectory(currentWorkingDir);
1072:                        } catch (IOException ioe) {
1073:                            getProject().log(
1074:                                    "could not cd back to " + dir
1075:                                            + " while checking a symlink",
1076:                                    Project.MSG_ERR);
1077:                        } finally {
1078:                            if (!comeback) {
1079:                                throw new BuildException(
1080:                                        "could not cd back to " + dir
1081:                                                + " while checking a symlink");
1082:                            }
1083:                        }
1084:                    }
1085:                }
1086:                return result;
1087:            }
1088:
1089:            /**
1090:             * check FTPFiles to check whether they function as directories too
1091:             * the FTPFile API seem to make directory and symbolic links incompatible
1092:             * we want to find out if we can cd to a symbolic link
1093:             * @param dir  the parent directory of the file to test
1094:             * @param file the file to test
1095:             * @return true if it is possible to cd to this directory
1096:             * @since ant 1.6
1097:             */
1098:            private boolean isFunctioningAsFile(FTPClient ftp, String dir,
1099:                    FTPFile file) {
1100:                if (file.isDirectory()) {
1101:                    return false;
1102:                } else if (file.isFile()) {
1103:                    return true;
1104:                }
1105:                return !isFunctioningAsDirectory(ftp, dir, file);
1106:            }
1107:
1108:            /**
1109:             * Sets the remote directory where files will be placed. This may be a
1110:             * relative or absolute path, and must be in the path syntax expected by
1111:             * the remote server. No correction of path syntax will be performed.
1112:             *
1113:             * @param dir the remote directory name.
1114:             */
1115:            public void setRemotedir(String dir) {
1116:                this .remotedir = dir;
1117:            }
1118:
1119:            /**
1120:             * Sets the FTP server to send files to.
1121:             *
1122:             * @param server the remote server name.
1123:             */
1124:            public void setServer(String server) {
1125:                this .server = server;
1126:            }
1127:
1128:            /**
1129:             * Sets the FTP port used by the remote server.
1130:             *
1131:             * @param port the port on which the remote server is listening.
1132:             */
1133:            public void setPort(int port) {
1134:                this .port = port;
1135:            }
1136:
1137:            /**
1138:             * Sets the login user id to use on the specified server.
1139:             *
1140:             * @param userid remote system userid.
1141:             */
1142:            public void setUserid(String userid) {
1143:                this .userid = userid;
1144:            }
1145:
1146:            /**
1147:             * Sets the login password for the given user id.
1148:             *
1149:             * @param password the password on the remote system.
1150:             */
1151:            public void setPassword(String password) {
1152:                this .password = password;
1153:            }
1154:
1155:            /**
1156:             * Sets the login account to use on the specified server.
1157:             *
1158:             * @param pAccount the account name on remote system
1159:             * @since Ant 1.7
1160:             */
1161:            public void setAccount(String pAccount) {
1162:                this .account = pAccount;
1163:            }
1164:
1165:            /**
1166:             * If true, uses binary mode, otherwise text mode (default is binary).
1167:             *
1168:             * @param binary if true use binary mode in transfers.
1169:             */
1170:            public void setBinary(boolean binary) {
1171:                this .binary = binary;
1172:            }
1173:
1174:            /**
1175:             * Specifies whether to use passive mode. Set to true if you are behind a
1176:             * firewall and cannot connect without it. Passive mode is disabled by
1177:             * default.
1178:             *
1179:             * @param passive true is passive mode should be used.
1180:             */
1181:            public void setPassive(boolean passive) {
1182:                this .passive = passive;
1183:            }
1184:
1185:            /**
1186:             * Set to true to receive notification about each file as it is
1187:             * transferred.
1188:             *
1189:             * @param verbose true if verbose notifications are required.
1190:             */
1191:            public void setVerbose(boolean verbose) {
1192:                this .verbose = verbose;
1193:            }
1194:
1195:            /**
1196:             * A synonym for <tt>depends</tt>. Set to true to transmit only new
1197:             * or changed files.
1198:             *
1199:             * See the related attributes timediffmillis and timediffauto.
1200:             *
1201:             * @param newer if true only transfer newer files.
1202:             */
1203:            public void setNewer(boolean newer) {
1204:                this .newerOnly = newer;
1205:            }
1206:
1207:            /**
1208:             * number of milliseconds to add to the time on the remote machine
1209:             * to get the time on the local machine.
1210:             *
1211:             * use in conjunction with <code>newer</code>
1212:             *
1213:             * @param timeDiffMillis number of milliseconds
1214:             *
1215:             * @since ant 1.6
1216:             */
1217:            public void setTimeDiffMillis(long timeDiffMillis) {
1218:                this .timeDiffMillis = timeDiffMillis;
1219:            }
1220:
1221:            /**
1222:             * &quot;true&quot; to find out automatically the time difference
1223:             * between local and remote machine.
1224:             *
1225:             * This requires right to create
1226:             * and delete a temporary file in the remote directory.
1227:             *
1228:             * @param timeDiffAuto true = find automatically the time diff
1229:             *
1230:             * @since ant 1.6
1231:             */
1232:            public void setTimeDiffAuto(boolean timeDiffAuto) {
1233:                this .timeDiffAuto = timeDiffAuto;
1234:            }
1235:
1236:            /**
1237:             * Set to true to preserve modification times for "gotten" files.
1238:             *
1239:             * @param preserveLastModified if true preserver modification times.
1240:             */
1241:            public void setPreserveLastModified(boolean preserveLastModified) {
1242:                this .preserveLastModified = preserveLastModified;
1243:            }
1244:
1245:            /**
1246:             * Set to true to transmit only files that are new or changed from their
1247:             * remote counterparts. The default is to transmit all files.
1248:             *
1249:             * @param depends if true only transfer newer files.
1250:             */
1251:            public void setDepends(boolean depends) {
1252:                this .newerOnly = depends;
1253:            }
1254:
1255:            /**
1256:             * Sets the remote file separator character. This normally defaults to the
1257:             * Unix standard forward slash, but can be manually overridden using this
1258:             * call if the remote server requires some other separator. Only the first
1259:             * character of the string is used.
1260:             *
1261:             * @param separator the file separator on the remote system.
1262:             */
1263:            public void setSeparator(String separator) {
1264:                remoteFileSep = separator;
1265:            }
1266:
1267:            /**
1268:             * Sets the file permission mode (Unix only) for files sent to the
1269:             * server.
1270:             *
1271:             * @param theMode unix style file mode for the files sent to the remote
1272:             *        system.
1273:             */
1274:            public void setChmod(String theMode) {
1275:                this .chmod = theMode;
1276:            }
1277:
1278:            /**
1279:             * Sets the default mask for file creation on a unix server.
1280:             *
1281:             * @param theUmask unix style umask for files created on the remote server.
1282:             */
1283:            public void setUmask(String theUmask) {
1284:                this .umask = theUmask;
1285:            }
1286:
1287:            /**
1288:             *  A set of files to upload or download
1289:             *
1290:             * @param set the set of files to be added to the list of files to be
1291:             *        transferred.
1292:             */
1293:            public void addFileset(FileSet set) {
1294:                filesets.addElement(set);
1295:            }
1296:
1297:            /**
1298:             * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
1299:             * "mkdir", "chmod", "list", and "site".
1300:             *
1301:             * @deprecated since 1.5.x.
1302:             *             setAction(String) is deprecated and is replaced with
1303:             *      setAction(FTP.Action) to make Ant's Introspection mechanism do the
1304:             *      work and also to encapsulate operations on the type in its own
1305:             *      class.
1306:             * @ant.attribute ignore="true"
1307:             *
1308:             * @param action the FTP action to be performed.
1309:             *
1310:             * @throws BuildException if the action is not a valid action.
1311:             */
1312:            public void setAction(String action) throws BuildException {
1313:                log("DEPRECATED - The setAction(String) method has been deprecated."
1314:                        + " Use setAction(FTP.Action) instead.");
1315:
1316:                Action a = new Action();
1317:
1318:                a.setValue(action);
1319:                this .action = a.getAction();
1320:            }
1321:
1322:            /**
1323:             * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
1324:             * "mkdir", "chmod", "list", and "site".
1325:             *
1326:             * @param action the FTP action to be performed.
1327:             *
1328:             * @throws BuildException if the action is not a valid action.
1329:             */
1330:            public void setAction(Action action) throws BuildException {
1331:                this .action = action.getAction();
1332:            }
1333:
1334:            /**
1335:             * The output file for the "list" action. This attribute is ignored for
1336:             * any other actions.
1337:             *
1338:             * @param listing file in which to store the listing.
1339:             */
1340:            public void setListing(File listing) {
1341:                this .listing = listing;
1342:            }
1343:
1344:            /**
1345:             * If true, enables unsuccessful file put, delete and get
1346:             * operations to be skipped with a warning and the remainder
1347:             * of the files still transferred.
1348:             *
1349:             * @param skipFailedTransfers true if failures in transfers are ignored.
1350:             */
1351:            public void setSkipFailedTransfers(boolean skipFailedTransfers) {
1352:                this .skipFailedTransfers = skipFailedTransfers;
1353:            }
1354:
1355:            /**
1356:             * set the flag to skip errors on directory creation.
1357:             * (and maybe later other server specific errors)
1358:             *
1359:             * @param ignoreNoncriticalErrors true if non-critical errors should not
1360:             *        cause a failure.
1361:             */
1362:            public void setIgnoreNoncriticalErrors(
1363:                    boolean ignoreNoncriticalErrors) {
1364:                this .ignoreNoncriticalErrors = ignoreNoncriticalErrors;
1365:            }
1366:
1367:            private void configurationHasBeenSet() {
1368:                this .isConfigurationSet = true;
1369:            }
1370:
1371:            /**
1372:             * Sets the systemTypeKey attribute.
1373:             * Method for setting <code>FTPClientConfig</code> remote system key.
1374:             *
1375:             * @param systemKey the key to be set - BUT if blank
1376:             * the default value of null (which signifies "autodetect") will be kept.
1377:             * @see org.apache.commons.net.ftp.FTPClientConfig
1378:             */
1379:            public void setSystemTypeKey(FTPSystemType systemKey) {
1380:                if (systemKey != null && !systemKey.getValue().equals("")) {
1381:                    this .systemTypeKey = systemKey;
1382:                    configurationHasBeenSet();
1383:                }
1384:            }
1385:
1386:            /**
1387:             * Sets the defaultDateFormatConfig attribute.
1388:             * @param defaultDateFormat configuration to be set, unless it is
1389:             * null or empty string, in which case ignored.
1390:             * @see org.apache.commons.net.ftp.FTPClientConfig
1391:             */
1392:            public void setDefaultDateFormatConfig(String defaultDateFormat) {
1393:                if (defaultDateFormat != null && !defaultDateFormat.equals("")) {
1394:                    this .defaultDateFormatConfig = defaultDateFormat;
1395:                    configurationHasBeenSet();
1396:                }
1397:            }
1398:
1399:            /**
1400:             * Sets the recentDateFormatConfig attribute.
1401:             * @param recentDateFormat configuration to be set, unless it is
1402:             * null or empty string, in which case ignored.
1403:             * @see org.apache.commons.net.ftp.FTPClientConfig
1404:             */
1405:            public void setRecentDateFormatConfig(String recentDateFormat) {
1406:                if (recentDateFormat != null && !recentDateFormat.equals("")) {
1407:                    this .recentDateFormatConfig = recentDateFormat;
1408:                    configurationHasBeenSet();
1409:                }
1410:            }
1411:
1412:            /**
1413:             * Sets the serverLanguageCode attribute.
1414:             * @param serverLanguageCode configuration to be set, unless it is
1415:             * null or empty string, in which case ignored.
1416:             * @see org.apache.commons.net.ftp.FTPClientConfig
1417:             */
1418:            public void setServerLanguageCodeConfig(
1419:                    LanguageCode serverLanguageCode) {
1420:                if (serverLanguageCode != null
1421:                        && !serverLanguageCode.equals("")) {
1422:                    this .serverLanguageCodeConfig = serverLanguageCode;
1423:                    configurationHasBeenSet();
1424:                }
1425:            }
1426:
1427:            /**
1428:             * Sets the serverTimeZoneConfig attribute.
1429:             * @param serverTimeZoneId configuration to be set, unless it is
1430:             * null or empty string, in which case ignored.
1431:             * @see org.apache.commons.net.ftp.FTPClientConfig
1432:             */
1433:            public void setServerTimeZoneConfig(String serverTimeZoneId) {
1434:                if (serverTimeZoneId != null && !serverTimeZoneId.equals("")) {
1435:                    this .serverTimeZoneConfig = serverTimeZoneId;
1436:                    configurationHasBeenSet();
1437:                }
1438:            }
1439:
1440:            /**
1441:             * Sets the shortMonthNamesConfig attribute
1442:             *
1443:             * @param shortMonthNames configuration to be set, unless it is
1444:             * null or empty string, in which case ignored.
1445:             * @see org.apache.commons.net.ftp.FTPClientConfig
1446:             */
1447:            public void setShortMonthNamesConfig(String shortMonthNames) {
1448:                if (shortMonthNames != null && !shortMonthNames.equals("")) {
1449:                    this .shortMonthNamesConfig = shortMonthNames;
1450:                    configurationHasBeenSet();
1451:                }
1452:            }
1453:
1454:            /**
1455:             * Defines how many times to retry executing FTP command before giving up.
1456:             * Default is 0 - try once and if failure then give up.
1457:             *
1458:             * @param retriesAllowed number of retries to allow.  -1 means
1459:             * keep trying forever. "forever" may also be specified as a
1460:             * synonym for -1.
1461:             */
1462:            public void setRetriesAllowed(String retriesAllowed) {
1463:                if ("FOREVER".equalsIgnoreCase(retriesAllowed)) {
1464:                    this .retriesAllowed = Retryable.RETRY_FOREVER;
1465:                } else {
1466:                    try {
1467:                        int retries = Integer.parseInt(retriesAllowed);
1468:                        if (retries < Retryable.RETRY_FOREVER) {
1469:                            throw new BuildException(
1470:                                    "Invalid value for retriesAllowed attribute: "
1471:                                            + retriesAllowed);
1472:
1473:                        }
1474:                        this .retriesAllowed = retries;
1475:                    } catch (NumberFormatException px) {
1476:                        throw new BuildException(
1477:                                "Invalid value for retriesAllowed attribute: "
1478:                                        + retriesAllowed);
1479:
1480:                    }
1481:
1482:                }
1483:            }
1484:
1485:            /**
1486:             * @return Returns the systemTypeKey.
1487:             */
1488:            String getSystemTypeKey() {
1489:                return systemTypeKey.getValue();
1490:            }
1491:
1492:            /**
1493:             * @return Returns the defaultDateFormatConfig.
1494:             */
1495:            String getDefaultDateFormatConfig() {
1496:                return defaultDateFormatConfig;
1497:            }
1498:
1499:            /**
1500:             * @return Returns the recentDateFormatConfig.
1501:             */
1502:            String getRecentDateFormatConfig() {
1503:                return recentDateFormatConfig;
1504:            }
1505:
1506:            /**
1507:             * @return Returns the serverLanguageCodeConfig.
1508:             */
1509:            String getServerLanguageCodeConfig() {
1510:                return serverLanguageCodeConfig.getValue();
1511:            }
1512:
1513:            /**
1514:             * @return Returns the serverTimeZoneConfig.
1515:             */
1516:            String getServerTimeZoneConfig() {
1517:                return serverTimeZoneConfig;
1518:            }
1519:
1520:            /**
1521:             * @return Returns the shortMonthNamesConfig.
1522:             */
1523:            String getShortMonthNamesConfig() {
1524:                return shortMonthNamesConfig;
1525:            }
1526:
1527:            /**
1528:             * @return Returns the timestampGranularity.
1529:             */
1530:            Granularity getTimestampGranularity() {
1531:                return timestampGranularity;
1532:            }
1533:
1534:            /**
1535:             * Sets the timestampGranularity attribute
1536:             * @param timestampGranularity The timestampGranularity to set.
1537:             */
1538:            public void setTimestampGranularity(Granularity timestampGranularity) {
1539:                if (null == timestampGranularity
1540:                        || "".equals(timestampGranularity)) {
1541:                    return;
1542:                }
1543:                this .timestampGranularity = timestampGranularity;
1544:            }
1545:
1546:            /**
1547:             * Sets the siteCommand attribute.  This attribute
1548:             * names the command that will be executed if the action
1549:             * is "site".
1550:             * @param siteCommand The siteCommand to set.
1551:             */
1552:            public void setSiteCommand(String siteCommand) {
1553:                this .siteCommand = siteCommand;
1554:            }
1555:
1556:            /**
1557:             * Sets the initialSiteCommand attribute.  This attribute
1558:             * names a site command that will be executed immediately
1559:             * after connection.
1560:             * @param initialCommand The initialSiteCommand to set.
1561:             */
1562:            public void setInitialSiteCommand(String initialCommand) {
1563:                this .initialSiteCommand = initialCommand;
1564:            }
1565:
1566:            /**
1567:             * Checks to see that all required parameters are set.
1568:             *
1569:             * @throws BuildException if the configuration is not valid.
1570:             */
1571:            protected void checkAttributes() throws BuildException {
1572:                if (server == null) {
1573:                    throw new BuildException("server attribute must be set!");
1574:                }
1575:                if (userid == null) {
1576:                    throw new BuildException("userid attribute must be set!");
1577:                }
1578:                if (password == null) {
1579:                    throw new BuildException("password attribute must be set!");
1580:                }
1581:
1582:                if ((action == LIST_FILES) && (listing == null)) {
1583:                    throw new BuildException(
1584:                            "listing attribute must be set for list "
1585:                                    + "action!");
1586:                }
1587:
1588:                if (action == MK_DIR && remotedir == null) {
1589:                    throw new BuildException(
1590:                            "remotedir attribute must be set for "
1591:                                    + "mkdir action!");
1592:                }
1593:
1594:                if (action == CHMOD && chmod == null) {
1595:                    throw new BuildException(
1596:                            "chmod attribute must be set for chmod "
1597:                                    + "action!");
1598:                }
1599:                if (action == SITE_CMD && siteCommand == null) {
1600:                    throw new BuildException(
1601:                            "sitecommand attribute must be set for site "
1602:                                    + "action!");
1603:                }
1604:
1605:                if (this .isConfigurationSet) {
1606:                    try {
1607:                        Class
1608:                                .forName("org.apache.commons.net.ftp.FTPClientConfig");
1609:                    } catch (ClassNotFoundException e) {
1610:                        throw new BuildException(
1611:                                "commons-net.jar >= 1.4.0 is required for at least one"
1612:                                        + " of the attributes specified.");
1613:                    }
1614:                }
1615:            }
1616:
1617:            /**
1618:             * Executable a retryable object.
1619:             * @param h the retry hander.
1620:             * @param r the object that should be retried until it succeeds
1621:             *          or the number of retrys is reached.
1622:             * @param descr a description of the command that is being run.
1623:             * @throws IOException if there is a problem.
1624:             */
1625:            protected void executeRetryable(RetryHandler h, Retryable r,
1626:                    String descr) throws IOException {
1627:                h.execute(r, descr);
1628:            }
1629:
1630:            /**
1631:             * For each file in the fileset, do the appropriate action: send, get,
1632:             * delete, or list.
1633:             *
1634:             * @param ftp the FTPClient instance used to perform FTP actions
1635:             * @param fs the fileset on which the actions are performed.
1636:             *
1637:             * @return the number of files to be transferred.
1638:             *
1639:             * @throws IOException if there is a problem reading a file
1640:             * @throws BuildException if there is a problem in the configuration.
1641:             */
1642:            protected int transferFiles(final FTPClient ftp, FileSet fs)
1643:                    throws IOException, BuildException {
1644:                DirectoryScanner ds;
1645:                if (action == SEND_FILES) {
1646:                    ds = fs.getDirectoryScanner(getProject());
1647:                } else {
1648:                    // warn that selectors are not supported
1649:                    if (fs.getSelectors(getProject()).length != 0) {
1650:                        getProject()
1651:                                .log(
1652:                                        "selectors are not supported in remote filesets",
1653:                                        Project.MSG_WARN);
1654:                    }
1655:                    ds = new FTPDirectoryScanner(ftp);
1656:                    fs.setupDirectoryScanner(ds, getProject());
1657:                    ds.setFollowSymlinks(fs.isFollowSymlinks());
1658:                    ds.scan();
1659:                }
1660:
1661:                String[] dsfiles = null;
1662:                if (action == RM_DIR) {
1663:                    dsfiles = ds.getIncludedDirectories();
1664:                } else {
1665:                    dsfiles = ds.getIncludedFiles();
1666:                }
1667:                String dir = null;
1668:
1669:                if ((ds.getBasedir() == null)
1670:                        && ((action == SEND_FILES) || (action == GET_FILES))) {
1671:                    throw new BuildException(
1672:                            "the dir attribute must be set for send "
1673:                                    + "and get actions");
1674:                } else {
1675:                    if ((action == SEND_FILES) || (action == GET_FILES)) {
1676:                        dir = ds.getBasedir().getAbsolutePath();
1677:                    }
1678:                }
1679:
1680:                // If we are doing a listing, we need the output stream created now.
1681:                BufferedWriter bw = null;
1682:
1683:                try {
1684:                    if (action == LIST_FILES) {
1685:                        File pd = listing.getParentFile();
1686:
1687:                        if (!pd.exists()) {
1688:                            pd.mkdirs();
1689:                        }
1690:                        bw = new BufferedWriter(new FileWriter(listing));
1691:                    }
1692:                    RetryHandler h = new RetryHandler(this .retriesAllowed, this );
1693:                    if (action == RM_DIR) {
1694:                        // to remove directories, start by the end of the list
1695:                        // the trunk does not let itself be removed before the leaves
1696:                        for (int i = dsfiles.length - 1; i >= 0; i--) {
1697:                            final String dsfile = dsfiles[i];
1698:                            executeRetryable(h, new Retryable() {
1699:                                public void execute() throws IOException {
1700:                                    rmDir(ftp, dsfile);
1701:                                }
1702:                            }, dsfile);
1703:                        }
1704:                    } else {
1705:                        final BufferedWriter fbw = bw;
1706:                        final String fdir = dir;
1707:                        if (this .newerOnly) {
1708:                            this .granularityMillis = this .timestampGranularity
1709:                                    .getMilliseconds(action);
1710:                        }
1711:                        for (int i = 0; i < dsfiles.length; i++) {
1712:                            final String dsfile = dsfiles[i];
1713:                            executeRetryable(h, new Retryable() {
1714:                                public void execute() throws IOException {
1715:                                    switch (action) {
1716:                                    case SEND_FILES:
1717:                                        sendFile(ftp, fdir, dsfile);
1718:                                        break;
1719:                                    case GET_FILES:
1720:                                        getFile(ftp, fdir, dsfile);
1721:                                        break;
1722:                                    case DEL_FILES:
1723:                                        delFile(ftp, dsfile);
1724:                                        break;
1725:                                    case LIST_FILES:
1726:                                        listFile(ftp, fbw, dsfile);
1727:                                        break;
1728:                                    case CHMOD:
1729:                                        doSiteCommand(ftp, "chmod " + chmod
1730:                                                + " " + resolveFile(dsfile));
1731:                                        transferred++;
1732:                                        break;
1733:                                    default:
1734:                                        throw new BuildException(
1735:                                                "unknown ftp action " + action);
1736:                                    }
1737:                                }
1738:                            }, dsfile);
1739:                        }
1740:                    }
1741:                } finally {
1742:                    if (bw != null) {
1743:                        bw.close();
1744:                    }
1745:                }
1746:
1747:                return dsfiles.length;
1748:            }
1749:
1750:            /**
1751:             * Sends all files specified by the configured filesets to the remote
1752:             * server.
1753:             *
1754:             * @param ftp the FTPClient instance used to perform FTP actions
1755:             *
1756:             * @throws IOException if there is a problem reading a file
1757:             * @throws BuildException if there is a problem in the configuration.
1758:             */
1759:            protected void transferFiles(FTPClient ftp) throws IOException,
1760:                    BuildException {
1761:                transferred = 0;
1762:                skipped = 0;
1763:
1764:                if (filesets.size() == 0) {
1765:                    throw new BuildException(
1766:                            "at least one fileset must be specified.");
1767:                } else {
1768:                    // get files from filesets
1769:                    for (int i = 0; i < filesets.size(); i++) {
1770:                        FileSet fs = (FileSet) filesets.elementAt(i);
1771:
1772:                        if (fs != null) {
1773:                            transferFiles(ftp, fs);
1774:                        }
1775:                    }
1776:                }
1777:
1778:                log(transferred + " " + ACTION_TARGET_STRS[action] + " "
1779:                        + COMPLETED_ACTION_STRS[action]);
1780:                if (skipped != 0) {
1781:                    log(skipped + " " + ACTION_TARGET_STRS[action]
1782:                            + " were not successfully "
1783:                            + COMPLETED_ACTION_STRS[action]);
1784:                }
1785:            }
1786:
1787:            /**
1788:             * Correct a file path to correspond to the remote host requirements. This
1789:             * implementation currently assumes that the remote end can handle
1790:             * Unix-style paths with forward-slash separators. This can be overridden
1791:             * with the <code>separator</code> task parameter. No attempt is made to
1792:             * determine what syntax is appropriate for the remote host.
1793:             *
1794:             * @param file the remote file name to be resolved
1795:             *
1796:             * @return the filename as it will appear on the server.
1797:             */
1798:            protected String resolveFile(String file) {
1799:                return file.replace(System.getProperty("file.separator")
1800:                        .charAt(0), remoteFileSep.charAt(0));
1801:            }
1802:
1803:            /**
1804:             * Creates all parent directories specified in a complete relative
1805:             * pathname. Attempts to create existing directories will not cause
1806:             * errors.
1807:             *
1808:             * @param ftp the FTP client instance to use to execute FTP actions on
1809:             *        the remote server.
1810:             * @param filename the name of the file whose parents should be created.
1811:             * @throws IOException under non documented circumstances
1812:             * @throws BuildException if it is impossible to cd to a remote directory
1813:             *
1814:             */
1815:            protected void createParents(FTPClient ftp, String filename)
1816:                    throws IOException, BuildException {
1817:
1818:                File dir = new File(filename);
1819:                if (dirCache.contains(dir)) {
1820:                    return;
1821:                }
1822:
1823:                Vector parents = new Vector();
1824:                String dirname;
1825:
1826:                while ((dirname = dir.getParent()) != null) {
1827:                    File checkDir = new File(dirname);
1828:                    if (dirCache.contains(checkDir)) {
1829:                        break;
1830:                    }
1831:                    dir = checkDir;
1832:                    parents.addElement(dir);
1833:                }
1834:
1835:                // find first non cached dir
1836:                int i = parents.size() - 1;
1837:
1838:                if (i >= 0) {
1839:                    String cwd = ftp.printWorkingDirectory();
1840:                    String parent = dir.getParent();
1841:                    if (parent != null) {
1842:                        if (!ftp.changeWorkingDirectory(resolveFile(parent))) {
1843:                            throw new BuildException("could not change to "
1844:                                    + "directory: " + ftp.getReplyString());
1845:                        }
1846:                    }
1847:
1848:                    while (i >= 0) {
1849:                        dir = (File) parents.elementAt(i--);
1850:                        // check if dir exists by trying to change into it.
1851:                        if (!ftp.changeWorkingDirectory(dir.getName())) {
1852:                            // could not change to it - try to create it
1853:                            log("creating remote directory "
1854:                                    + resolveFile(dir.getPath()),
1855:                                    Project.MSG_VERBOSE);
1856:                            if (!ftp.makeDirectory(dir.getName())) {
1857:                                handleMkDirFailure(ftp);
1858:                            }
1859:                            if (!ftp.changeWorkingDirectory(dir.getName())) {
1860:                                throw new BuildException("could not change to "
1861:                                        + "directory: " + ftp.getReplyString());
1862:                            }
1863:                        }
1864:                        dirCache.addElement(dir);
1865:                    }
1866:                    ftp.changeWorkingDirectory(cwd);
1867:                }
1868:            }
1869:
1870:            /**
1871:             * auto find the time difference between local and remote
1872:             * @param ftp handle to ftp client
1873:             * @return number of millis to add to remote time to make it comparable to local time
1874:             * @since ant 1.6
1875:             */
1876:            private long getTimeDiff(FTPClient ftp) {
1877:                long returnValue = 0;
1878:                File tempFile = findFileName(ftp);
1879:                try {
1880:                    // create a local temporary file
1881:                    FILE_UTILS.createNewFile(tempFile);
1882:                    long localTimeStamp = tempFile.lastModified();
1883:                    BufferedInputStream instream = new BufferedInputStream(
1884:                            new FileInputStream(tempFile));
1885:                    ftp.storeFile(tempFile.getName(), instream);
1886:                    instream.close();
1887:                    boolean success = FTPReply.isPositiveCompletion(ftp
1888:                            .getReplyCode());
1889:                    if (success) {
1890:                        FTPFile[] ftpFiles = ftp.listFiles(tempFile.getName());
1891:                        if (ftpFiles.length == 1) {
1892:                            long remoteTimeStamp = ftpFiles[0].getTimestamp()
1893:                                    .getTime().getTime();
1894:                            returnValue = localTimeStamp - remoteTimeStamp;
1895:                        }
1896:                        ftp.deleteFile(ftpFiles[0].getName());
1897:                    }
1898:                    // delegate the deletion of the local temp file to the delete task
1899:                    // because of race conditions occuring on Windows
1900:                    Delete mydelete = new Delete();
1901:                    mydelete.bindToOwner(this );
1902:                    mydelete.setFile(tempFile.getCanonicalFile());
1903:                    mydelete.execute();
1904:                } catch (Exception e) {
1905:                    throw new BuildException(e, getLocation());
1906:                }
1907:                return returnValue;
1908:            }
1909:
1910:            /**
1911:             *  find a suitable name for local and remote temporary file
1912:             */
1913:            private File findFileName(FTPClient ftp) {
1914:                FTPFile[] theFiles = null;
1915:                final int maxIterations = 1000;
1916:                for (int counter = 1; counter < maxIterations; counter++) {
1917:                    File localFile = FILE_UTILS.createTempFile("ant"
1918:                            + Integer.toString(counter), ".tmp", null);
1919:                    String fileName = localFile.getName();
1920:                    boolean found = false;
1921:                    try {
1922:                        if (counter == 1) {
1923:                            theFiles = ftp.listFiles();
1924:                        }
1925:                        for (int counter2 = 0; counter2 < theFiles.length; counter2++) {
1926:                            if (theFiles[counter2].getName().equals(fileName)) {
1927:                                found = true;
1928:                                break;
1929:                            }
1930:                        }
1931:                    } catch (IOException ioe) {
1932:                        throw new BuildException(ioe, getLocation());
1933:                    }
1934:                    if (!found) {
1935:                        localFile.deleteOnExit();
1936:                        return localFile;
1937:                    }
1938:                }
1939:                return null;
1940:            }
1941:
1942:            private static final SimpleDateFormat TIMESTAMP_LOGGING_SDF = new SimpleDateFormat(
1943:                    "yyyy-MM-dd HH:mm:ss");
1944:
1945:            /**
1946:             * Checks to see if the remote file is current as compared with the local
1947:             * file. Returns true if the target file is up to date.
1948:             * @param ftp ftpclient
1949:             * @param localFile local file
1950:             * @param remoteFile remote file
1951:             * @return true if the target file is up to date
1952:             * @throws IOException  in unknown circumstances
1953:             * @throws BuildException if the date of the remote files cannot be found and the action is
1954:             * GET_FILES
1955:             */
1956:            protected boolean isUpToDate(FTPClient ftp, File localFile,
1957:                    String remoteFile) throws IOException, BuildException {
1958:                log("checking date for " + remoteFile, Project.MSG_VERBOSE);
1959:
1960:                FTPFile[] files = ftp.listFiles(remoteFile);
1961:
1962:                // For Microsoft's Ftp-Service an Array with length 0 is
1963:                // returned if configured to return listings in "MS-DOS"-Format
1964:                if (files == null || files.length == 0) {
1965:                    // If we are sending files, then assume out of date.
1966:                    // If we are getting files, then throw an error
1967:
1968:                    if (action == SEND_FILES) {
1969:                        log("Could not date test remote file: " + remoteFile
1970:                                + "assuming out of date.", Project.MSG_VERBOSE);
1971:                        return false;
1972:                    } else {
1973:                        throw new BuildException(
1974:                                "could not date test remote file: "
1975:                                        + ftp.getReplyString());
1976:                    }
1977:                }
1978:
1979:                long remoteTimestamp = files[0].getTimestamp().getTime()
1980:                        .getTime();
1981:                long localTimestamp = localFile.lastModified();
1982:                long adjustedRemoteTimestamp = remoteTimestamp
1983:                        + this .timeDiffMillis + this .granularityMillis;
1984:
1985:                StringBuffer msg = new StringBuffer("   [").append(
1986:                        TIMESTAMP_LOGGING_SDF.format(new Date(localTimestamp)))
1987:                        .append("] local");
1988:                log(msg.toString(), Project.MSG_VERBOSE);
1989:
1990:                msg = new StringBuffer("   [").append(
1991:                        TIMESTAMP_LOGGING_SDF.format(new Date(
1992:                                adjustedRemoteTimestamp))).append("] remote");
1993:                if (remoteTimestamp != adjustedRemoteTimestamp) {
1994:                    msg.append(" - (raw: ").append(
1995:                            TIMESTAMP_LOGGING_SDF.format(new Date(
1996:                                    remoteTimestamp))).append(")");
1997:                }
1998:                log(msg.toString(), Project.MSG_VERBOSE);
1999:
2000:                if (this .action == SEND_FILES) {
2001:                    return adjustedRemoteTimestamp >= localTimestamp;
2002:                } else {
2003:                    return localTimestamp >= adjustedRemoteTimestamp;
2004:                }
2005:            }
2006:
2007:            /**
2008:             * Sends a site command to the ftp server
2009:             * @param ftp ftp client
2010:             * @param theCMD command to execute
2011:             * @throws IOException  in unknown circumstances
2012:             * @throws BuildException in unknown circumstances
2013:             */
2014:            protected void doSiteCommand(FTPClient ftp, String theCMD)
2015:                    throws IOException, BuildException {
2016:                boolean rc;
2017:                String[] myReply = null;
2018:
2019:                log("Doing Site Command: " + theCMD, Project.MSG_VERBOSE);
2020:
2021:                rc = ftp.sendSiteCommand(theCMD);
2022:
2023:                if (!rc) {
2024:                    log("Failed to issue Site Command: " + theCMD,
2025:                            Project.MSG_WARN);
2026:                } else {
2027:
2028:                    myReply = ftp.getReplyStrings();
2029:
2030:                    for (int x = 0; x < myReply.length; x++) {
2031:                        if (myReply[x].indexOf("200") == -1) {
2032:                            log(myReply[x], Project.MSG_WARN);
2033:                        }
2034:                    }
2035:                }
2036:            }
2037:
2038:            /**
2039:             * Sends a single file to the remote host. <code>filename</code> may
2040:             * contain a relative path specification. When this is the case, <code>sendFile</code>
2041:             * will attempt to create any necessary parent directories before sending
2042:             * the file. The file will then be sent using the entire relative path
2043:             * spec - no attempt is made to change directories. It is anticipated that
2044:             * this may eventually cause problems with some FTP servers, but it
2045:             * simplifies the coding.
2046:             * @param ftp ftp client
2047:             * @param dir base directory of the file to be sent (local)
2048:             * @param filename relative path of the file to be send
2049:             *        locally relative to dir
2050:             *        remotely relative to the remotedir attribute
2051:             * @throws IOException  in unknown circumstances
2052:             * @throws BuildException in unknown circumstances
2053:             */
2054:            protected void sendFile(FTPClient ftp, String dir, String filename)
2055:                    throws IOException, BuildException {
2056:                InputStream instream = null;
2057:
2058:                try {
2059:                    // XXX - why not simply new File(dir, filename)?
2060:                    File file = getProject().resolveFile(
2061:                            new File(dir, filename).getPath());
2062:
2063:                    if (newerOnly
2064:                            && isUpToDate(ftp, file, resolveFile(filename))) {
2065:                        return;
2066:                    }
2067:
2068:                    if (verbose) {
2069:                        log("transferring " + file.getAbsolutePath());
2070:                    }
2071:
2072:                    instream = new BufferedInputStream(
2073:                            new FileInputStream(file));
2074:
2075:                    createParents(ftp, filename);
2076:
2077:                    ftp.storeFile(resolveFile(filename), instream);
2078:
2079:                    boolean success = FTPReply.isPositiveCompletion(ftp
2080:                            .getReplyCode());
2081:
2082:                    if (!success) {
2083:                        String s = "could not put file: "
2084:                                + ftp.getReplyString();
2085:
2086:                        if (skipFailedTransfers) {
2087:                            log(s, Project.MSG_WARN);
2088:                            skipped++;
2089:                        } else {
2090:                            throw new BuildException(s);
2091:                        }
2092:
2093:                    } else {
2094:                        // see if we should issue a chmod command
2095:                        if (chmod != null) {
2096:                            doSiteCommand(ftp, "chmod " + chmod + " "
2097:                                    + resolveFile(filename));
2098:                        }
2099:                        log("File " + file.getAbsolutePath() + " copied to "
2100:                                + server, Project.MSG_VERBOSE);
2101:                        transferred++;
2102:                    }
2103:                } finally {
2104:                    if (instream != null) {
2105:                        try {
2106:                            instream.close();
2107:                        } catch (IOException ex) {
2108:                            // ignore it
2109:                        }
2110:                    }
2111:                }
2112:            }
2113:
2114:            /**
2115:             * Delete a file from the remote host.
2116:             * @param ftp ftp client
2117:             * @param filename file to delete
2118:             * @throws IOException  in unknown circumstances
2119:             * @throws BuildException if skipFailedTransfers is set to false
2120:             * and the deletion could not be done
2121:             */
2122:            protected void delFile(FTPClient ftp, String filename)
2123:                    throws IOException, BuildException {
2124:                if (verbose) {
2125:                    log("deleting " + filename);
2126:                }
2127:
2128:                if (!ftp.deleteFile(resolveFile(filename))) {
2129:                    String s = "could not delete file: " + ftp.getReplyString();
2130:
2131:                    if (skipFailedTransfers) {
2132:                        log(s, Project.MSG_WARN);
2133:                        skipped++;
2134:                    } else {
2135:                        throw new BuildException(s);
2136:                    }
2137:                } else {
2138:                    log("File " + filename + " deleted from " + server,
2139:                            Project.MSG_VERBOSE);
2140:                    transferred++;
2141:                }
2142:            }
2143:
2144:            /**
2145:             * Delete a directory, if empty, from the remote host.
2146:             * @param ftp ftp client
2147:             * @param dirname directory to delete
2148:             * @throws IOException  in unknown circumstances
2149:             * @throws BuildException if skipFailedTransfers is set to false
2150:             * and the deletion could not be done
2151:             */
2152:            protected void rmDir(FTPClient ftp, String dirname)
2153:                    throws IOException, BuildException {
2154:                if (verbose) {
2155:                    log("removing " + dirname);
2156:                }
2157:
2158:                if (!ftp.removeDirectory(resolveFile(dirname))) {
2159:                    String s = "could not remove directory: "
2160:                            + ftp.getReplyString();
2161:
2162:                    if (skipFailedTransfers) {
2163:                        log(s, Project.MSG_WARN);
2164:                        skipped++;
2165:                    } else {
2166:                        throw new BuildException(s);
2167:                    }
2168:                } else {
2169:                    log("Directory " + dirname + " removed from " + server,
2170:                            Project.MSG_VERBOSE);
2171:                    transferred++;
2172:                }
2173:            }
2174:
2175:            /**
2176:             * Retrieve a single file from the remote host. <code>filename</code> may
2177:             * contain a relative path specification. <p>
2178:             *
2179:             * The file will then be retreived using the entire relative path spec -
2180:             * no attempt is made to change directories. It is anticipated that this
2181:             * may eventually cause problems with some FTP servers, but it simplifies
2182:             * the coding.</p>
2183:             * @param ftp the ftp client
2184:             * @param dir local base directory to which the file should go back
2185:             * @param filename relative path of the file based upon the ftp remote directory
2186:             *        and/or the local base directory (dir)
2187:             * @throws IOException  in unknown circumstances
2188:             * @throws BuildException if skipFailedTransfers is false
2189:             * and the file cannot be retrieved.
2190:             */
2191:            protected void getFile(FTPClient ftp, String dir, String filename)
2192:                    throws IOException, BuildException {
2193:                OutputStream outstream = null;
2194:                try {
2195:                    File file = getProject().resolveFile(
2196:                            new File(dir, filename).getPath());
2197:
2198:                    if (newerOnly
2199:                            && isUpToDate(ftp, file, resolveFile(filename))) {
2200:                        return;
2201:                    }
2202:
2203:                    if (verbose) {
2204:                        log("transferring " + filename + " to "
2205:                                + file.getAbsolutePath());
2206:                    }
2207:
2208:                    File pdir = file.getParentFile();
2209:
2210:                    if (!pdir.exists()) {
2211:                        pdir.mkdirs();
2212:                    }
2213:                    outstream = new BufferedOutputStream(new FileOutputStream(
2214:                            file));
2215:                    ftp.retrieveFile(resolveFile(filename), outstream);
2216:
2217:                    if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
2218:                        String s = "could not get file: "
2219:                                + ftp.getReplyString();
2220:
2221:                        if (skipFailedTransfers) {
2222:                            log(s, Project.MSG_WARN);
2223:                            skipped++;
2224:                        } else {
2225:                            throw new BuildException(s);
2226:                        }
2227:
2228:                    } else {
2229:                        log("File " + file.getAbsolutePath() + " copied from "
2230:                                + server, Project.MSG_VERBOSE);
2231:                        transferred++;
2232:                        if (preserveLastModified) {
2233:                            outstream.close();
2234:                            outstream = null;
2235:                            FTPFile[] remote = ftp
2236:                                    .listFiles(resolveFile(filename));
2237:                            if (remote.length > 0) {
2238:                                FILE_UTILS.setFileLastModified(file, remote[0]
2239:                                        .getTimestamp().getTime().getTime());
2240:                            }
2241:                        }
2242:                    }
2243:                } finally {
2244:                    if (outstream != null) {
2245:                        try {
2246:                            outstream.close();
2247:                        } catch (IOException ex) {
2248:                            // ignore it
2249:                        }
2250:                    }
2251:                }
2252:            }
2253:
2254:            /**
2255:             * List information about a single file from the remote host. <code>filename</code>
2256:             * may contain a relative path specification. <p>
2257:             *
2258:             * The file listing will then be retrieved using the entire relative path
2259:             * spec - no attempt is made to change directories. It is anticipated that
2260:             * this may eventually cause problems with some FTP servers, but it
2261:             * simplifies the coding.</p>
2262:             * @param ftp ftp client
2263:             * @param bw buffered writer
2264:             * @param filename the directory one wants to list
2265:             * @throws IOException  in unknown circumstances
2266:             * @throws BuildException in unknown circumstances
2267:             */
2268:            protected void listFile(FTPClient ftp, BufferedWriter bw,
2269:                    String filename) throws IOException, BuildException {
2270:                if (verbose) {
2271:                    log("listing " + filename);
2272:                }
2273:                FTPFile[] ftpfiles = ftp.listFiles(resolveFile(filename));
2274:
2275:                if (ftpfiles != null && ftpfiles.length > 0) {
2276:                    bw.write(ftpfiles[0].toString());
2277:                    bw.newLine();
2278:                    transferred++;
2279:                }
2280:            }
2281:
2282:            /**
2283:             * Create the specified directory on the remote host.
2284:             *
2285:             * @param ftp The FTP client connection
2286:             * @param dir The directory to create (format must be correct for host
2287:             *      type)
2288:             * @throws IOException  in unknown circumstances
2289:             * @throws BuildException if ignoreNoncriticalErrors has not been set to true
2290:             *         and a directory could not be created, for instance because it was
2291:             *         already existing. Precisely, the codes 521, 550 and 553 will trigger
2292:             *         a BuildException
2293:             */
2294:            protected void makeRemoteDir(FTPClient ftp, String dir)
2295:                    throws IOException, BuildException {
2296:                String workingDirectory = ftp.printWorkingDirectory();
2297:                if (verbose) {
2298:                    log("Creating directory: " + dir);
2299:                }
2300:                if (dir.indexOf("/") == 0) {
2301:                    ftp.changeWorkingDirectory("/");
2302:                }
2303:                String subdir = new String();
2304:                StringTokenizer st = new StringTokenizer(dir, "/");
2305:                while (st.hasMoreTokens()) {
2306:                    subdir = st.nextToken();
2307:                    log("Checking " + subdir, Project.MSG_DEBUG);
2308:                    if (!ftp.changeWorkingDirectory(subdir)) {
2309:                        if (!ftp.makeDirectory(subdir)) {
2310:                            // codes 521, 550 and 553 can be produced by FTP Servers
2311:                            //  to indicate that an attempt to create a directory has
2312:                            //  failed because the directory already exists.
2313:                            int rc = ftp.getReplyCode();
2314:                            if (!(ignoreNoncriticalErrors && (rc == FTPReply.CODE_550
2315:                                    || rc == FTPReply.CODE_553 || rc == CODE_521))) {
2316:                                throw new BuildException(
2317:                                        "could not create directory: "
2318:                                                + ftp.getReplyString());
2319:                            }
2320:                            if (verbose) {
2321:                                log("Directory already exists");
2322:                            }
2323:                        } else {
2324:                            if (verbose) {
2325:                                log("Directory created OK");
2326:                            }
2327:                            ftp.changeWorkingDirectory(subdir);
2328:                        }
2329:                    }
2330:                }
2331:                if (workingDirectory != null) {
2332:                    ftp.changeWorkingDirectory(workingDirectory);
2333:                }
2334:            }
2335:
2336:            /**
2337:             * look at the response for a failed mkdir action, decide whether
2338:             * it matters or not. If it does, we throw an exception
2339:             * @param ftp current ftp connection
2340:             * @throws BuildException if this is an error to signal
2341:             */
2342:            private void handleMkDirFailure(FTPClient ftp)
2343:                    throws BuildException {
2344:                int rc = ftp.getReplyCode();
2345:                if (!(ignoreNoncriticalErrors && (rc == FTPReply.CODE_550
2346:                        || rc == FTPReply.CODE_553 || rc == CODE_521))) {
2347:                    throw new BuildException("could not create directory: "
2348:                            + ftp.getReplyString());
2349:                }
2350:            }
2351:
2352:            /**
2353:             * Runs the task.
2354:             *
2355:             * @throws BuildException if the task fails or is not configured
2356:             *         correctly.
2357:             */
2358:            public void execute() throws BuildException {
2359:                checkAttributes();
2360:
2361:                FTPClient ftp = null;
2362:
2363:                try {
2364:                    log("Opening FTP connection to " + server,
2365:                            Project.MSG_VERBOSE);
2366:
2367:                    ftp = new FTPClient();
2368:                    if (this .isConfigurationSet) {
2369:                        ftp = FTPConfigurator.configure(ftp, this );
2370:                    }
2371:
2372:                    ftp.connect(server, port);
2373:                    if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
2374:                        throw new BuildException("FTP connection failed: "
2375:                                + ftp.getReplyString());
2376:                    }
2377:
2378:                    log("connected", Project.MSG_VERBOSE);
2379:                    log("logging in to FTP server", Project.MSG_VERBOSE);
2380:
2381:                    if ((this .account != null && !ftp.login(userid, password,
2382:                            account))
2383:                            || (this .account == null && !ftp.login(userid,
2384:                                    password))) {
2385:                        throw new BuildException(
2386:                                "Could not login to FTP server");
2387:                    }
2388:
2389:                    log("login succeeded", Project.MSG_VERBOSE);
2390:
2391:                    if (binary) {
2392:                        ftp
2393:                                .setFileType(org.apache.commons.net.ftp.FTP.IMAGE_FILE_TYPE);
2394:                        if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
2395:                            throw new BuildException(
2396:                                    "could not set transfer type: "
2397:                                            + ftp.getReplyString());
2398:                        }
2399:                    } else {
2400:                        ftp
2401:                                .setFileType(org.apache.commons.net.ftp.FTP.ASCII_FILE_TYPE);
2402:                        if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
2403:                            throw new BuildException(
2404:                                    "could not set transfer type: "
2405:                                            + ftp.getReplyString());
2406:                        }
2407:                    }
2408:
2409:                    if (passive) {
2410:                        log("entering passive mode", Project.MSG_VERBOSE);
2411:                        ftp.enterLocalPassiveMode();
2412:                        if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
2413:                            throw new BuildException(
2414:                                    "could not enter into passive " + "mode: "
2415:                                            + ftp.getReplyString());
2416:                        }
2417:                    }
2418:
2419:                    // If an initial command was configured then send it.
2420:                    // Some FTP servers offer different modes of operation,
2421:                    // E.G. switching between a UNIX file system mode and
2422:                    // a legacy file system.
2423:                    if (this .initialSiteCommand != null) {
2424:                        RetryHandler h = new RetryHandler(this .retriesAllowed,
2425:                                this );
2426:                        final FTPClient lftp = ftp;
2427:                        executeRetryable(h, new Retryable() {
2428:                            public void execute() throws IOException {
2429:                                doSiteCommand(lftp, FTP.this .initialSiteCommand);
2430:                            }
2431:                        }, "initial site command: " + this .initialSiteCommand);
2432:                    }
2433:
2434:                    // For a unix ftp server you can set the default mask for all files
2435:                    // created.
2436:
2437:                    if (umask != null) {
2438:                        RetryHandler h = new RetryHandler(this .retriesAllowed,
2439:                                this );
2440:                        final FTPClient lftp = ftp;
2441:                        executeRetryable(h, new Retryable() {
2442:                            public void execute() throws IOException {
2443:                                doSiteCommand(lftp, "umask " + umask);
2444:                            }
2445:                        }, "umask " + umask);
2446:                    }
2447:
2448:                    // If the action is MK_DIR, then the specified remote
2449:                    // directory is the directory to create.
2450:
2451:                    if (action == MK_DIR) {
2452:                        RetryHandler h = new RetryHandler(this .retriesAllowed,
2453:                                this );
2454:                        final FTPClient lftp = ftp;
2455:                        executeRetryable(h, new Retryable() {
2456:                            public void execute() throws IOException {
2457:                                makeRemoteDir(lftp, remotedir);
2458:                            }
2459:                        }, remotedir);
2460:                    } else if (action == SITE_CMD) {
2461:                        RetryHandler h = new RetryHandler(this .retriesAllowed,
2462:                                this );
2463:                        final FTPClient lftp = ftp;
2464:                        executeRetryable(h, new Retryable() {
2465:                            public void execute() throws IOException {
2466:                                doSiteCommand(lftp, FTP.this .siteCommand);
2467:                            }
2468:                        }, "Site Command: " + this .siteCommand);
2469:                    } else {
2470:                        if (remotedir != null) {
2471:                            log("changing the remote directory",
2472:                                    Project.MSG_VERBOSE);
2473:                            ftp.changeWorkingDirectory(remotedir);
2474:                            if (!FTPReply.isPositiveCompletion(ftp
2475:                                    .getReplyCode())) {
2476:                                throw new BuildException(
2477:                                        "could not change remote "
2478:                                                + "directory: "
2479:                                                + ftp.getReplyString());
2480:                            }
2481:                        }
2482:                        if (newerOnly && timeDiffAuto) {
2483:                            // in this case we want to find how much time span there is between local
2484:                            // and remote
2485:                            timeDiffMillis = getTimeDiff(ftp);
2486:                        }
2487:                        log(ACTION_STRS[action] + " "
2488:                                + ACTION_TARGET_STRS[action]);
2489:                        transferFiles(ftp);
2490:                    }
2491:
2492:                } catch (IOException ex) {
2493:                    throw new BuildException(
2494:                            "error during FTP transfer: " + ex, ex);
2495:                } finally {
2496:                    if (ftp != null && ftp.isConnected()) {
2497:                        try {
2498:                            log("disconnecting", Project.MSG_VERBOSE);
2499:                            ftp.logout();
2500:                            ftp.disconnect();
2501:                        } catch (IOException ex) {
2502:                            // ignore it
2503:                        }
2504:                    }
2505:                }
2506:            }
2507:
2508:            /**
2509:             * an action to perform, one of
2510:             * "send", "put", "recv", "get", "del", "delete", "list", "mkdir", "chmod",
2511:             * "rmdir"
2512:             */
2513:            public static class Action extends EnumeratedAttribute {
2514:
2515:                private static final String[] VALID_ACTIONS = { "send", "put",
2516:                        "recv", "get", "del", "delete", "list", "mkdir",
2517:                        "chmod", "rmdir", "site" };
2518:
2519:                /**
2520:                 * Get the valid values
2521:                 *
2522:                 * @return an array of the valid FTP actions.
2523:                 */
2524:                public String[] getValues() {
2525:                    return VALID_ACTIONS;
2526:                }
2527:
2528:                /**
2529:                 * Get the symbolic equivalent of the action value.
2530:                 *
2531:                 * @return the SYMBOL representing the given action.
2532:                 */
2533:                public int getAction() {
2534:                    String actionL = getValue().toLowerCase(Locale.US);
2535:
2536:                    if (actionL.equals("send") || actionL.equals("put")) {
2537:                        return SEND_FILES;
2538:                    } else if (actionL.equals("recv") || actionL.equals("get")) {
2539:                        return GET_FILES;
2540:                    } else if (actionL.equals("del")
2541:                            || actionL.equals("delete")) {
2542:                        return DEL_FILES;
2543:                    } else if (actionL.equals("list")) {
2544:                        return LIST_FILES;
2545:                    } else if (actionL.equals("chmod")) {
2546:                        return CHMOD;
2547:                    } else if (actionL.equals("mkdir")) {
2548:                        return MK_DIR;
2549:                    } else if (actionL.equals("rmdir")) {
2550:                        return RM_DIR;
2551:                    } else if (actionL.equals("site")) {
2552:                        return SITE_CMD;
2553:                    }
2554:                    return SEND_FILES;
2555:                }
2556:            }
2557:
2558:            /**
2559:             * represents one of the valid timestamp adjustment values
2560:             * recognized by the <code>timestampGranularity</code> attribute.<p>
2561:
2562:             * A timestamp adjustment may be used in file transfers for checking
2563:             * uptodateness. MINUTE means to add one minute to the server
2564:             * timestamp.  This is done because FTP servers typically list
2565:             * timestamps HH:mm and client FileSystems typically use HH:mm:ss.
2566:             *
2567:             * The default is to use MINUTE for PUT actions and NONE for GET
2568:             * actions, since GETs have the <code>preserveLastModified</code>
2569:             * option, which takes care of the problem in most use cases where
2570:             * this level of granularity is an issue.
2571:             *
2572:             */
2573:            public static class Granularity extends EnumeratedAttribute {
2574:
2575:                private static final String[] VALID_GRANULARITIES = { "",
2576:                        "MINUTE", "NONE" };
2577:
2578:                /**
2579:                 * Get the valid values.
2580:                 * @return the list of valid Granularity values
2581:                 */
2582:                public String[] getValues() {
2583:                    // TODO Auto-generated method stub
2584:                    return VALID_GRANULARITIES;
2585:                }
2586:
2587:                /**
2588:                 * returns the number of milliseconds associated with
2589:                 * the attribute, which can vary in some cases depending
2590:                 * on the value of the action parameter.
2591:                 * @param action SEND_FILES or GET_FILES
2592:                 * @return the number of milliseconds associated with
2593:                 * the attribute, in the context of the supplied action
2594:                 */
2595:                public long getMilliseconds(int action) {
2596:                    String granularityU = getValue().toUpperCase(Locale.US);
2597:
2598:                    if ("".equals(granularityU)) {
2599:                        if (action == SEND_FILES) {
2600:                            return GRANULARITY_MINUTE;
2601:                        }
2602:                    } else if ("MINUTE".equals(granularityU)) {
2603:                        return GRANULARITY_MINUTE;
2604:                    }
2605:                    return 0L;
2606:                }
2607:
2608:                static final Granularity getDefault() {
2609:                    Granularity g = new Granularity();
2610:                    g.setValue("");
2611:                    return g;
2612:                }
2613:
2614:            }
2615:
2616:            /**
2617:             * one of the valid system type keys recognized by the systemTypeKey
2618:             * attribute.
2619:             */
2620:            public static class FTPSystemType extends EnumeratedAttribute {
2621:
2622:                private static final String[] VALID_SYSTEM_TYPES = { "",
2623:                        "UNIX", "VMS", "WINDOWS", "OS/2", "OS/400", "MVS" };
2624:
2625:                /**
2626:                 * Get the valid values.
2627:                 * @return the list of valid system types.
2628:                 */
2629:                public String[] getValues() {
2630:                    return VALID_SYSTEM_TYPES;
2631:                }
2632:
2633:                static final FTPSystemType getDefault() {
2634:                    FTPSystemType ftpst = new FTPSystemType();
2635:                    ftpst.setValue("");
2636:                    return ftpst;
2637:                }
2638:            }
2639:
2640:            /**
2641:             * Enumerated class for languages.
2642:             */
2643:            public static class LanguageCode extends EnumeratedAttribute {
2644:
2645:                private static final String[] VALID_LANGUAGE_CODES = getValidLanguageCodes();
2646:
2647:                private static String[] getValidLanguageCodes() {
2648:                    Collection c = FTPClientConfig.getSupportedLanguageCodes();
2649:                    String[] ret = new String[c.size() + 1];
2650:                    int i = 0;
2651:                    ret[i++] = "";
2652:                    for (Iterator it = c.iterator(); it.hasNext(); i++) {
2653:                        ret[i] = (String) it.next();
2654:                    }
2655:                    return ret;
2656:                }
2657:
2658:                /**
2659:                 * Return the value values.
2660:                 * @return the list of valid language types.
2661:                 */
2662:                public String[] getValues() {
2663:                    return VALID_LANGUAGE_CODES;
2664:                }
2665:
2666:                static final LanguageCode getDefault() {
2667:                    LanguageCode lc = new LanguageCode();
2668:                    lc.setValue("");
2669:                    return lc;
2670:                }
2671:            }
2672:
2673:        }
w__w__w__._ja___v___a_2s_._co__m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.