| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.net.ftp.parser; |
| |
| import java.io.File; |
| import java.text.ParseException; |
| import java.util.Locale; |
| |
| import org.apache.commons.net.ftp.FTPClientConfig; |
| import org.apache.commons.net.ftp.FTPFile; |
| |
| /** |
| * <pre> |
| * Example *FILE/*MEM FTP entries, when the current |
| * working directory is a file of file system QSYS: |
| * ------------------------------------------------ |
| * |
| * $ cwd /qsys.lib/rpgunit.lib/rpgunitc1.file |
| * 250-NAMEFMT set to 1. |
| * 250 "/QSYS.LIB/RPGUNIT.LIB/RPGUNITC1.FILE" is current directory. |
| * $ dir |
| * 227 Entering Passive Mode (10,200,36,33,40,249). |
| * 125 List started. |
| * QPGMR 135168 22.06.13 13:18:19 *FILE |
| * QPGMR *MEM MKCMD.MBR |
| * QPGMR *MEM RUCALLTST.MBR |
| * QPGMR *MEM RUCMDHLP.MBR |
| * QPGMR *MEM RUCRTTST.MBR |
| * 250 List completed. |
| * |
| * |
| * Example *FILE entry of an OS/400 save file: |
| * --------------------------------------------------- |
| * |
| * $ cwd /qsys.lib/rpgunit.lib |
| * 250 "/QSYS.LIB/RPGUNIT.LIB" is current library. |
| * $ dir rpgunit.file |
| * 227 Entering Passive Mode (10,200,36,33,188,106). |
| * 125 List started. |
| * QPGMR 16347136 29.06.13 15:45:09 *FILE RPGUNIT.SAVF |
| * 250 List completed. |
| * |
| * |
| * Example *STMF/*DIR FTP entries, when the |
| * current working directory is in file system "root": |
| * --------------------------------------------------- |
| * |
| * $ cwd /home/raddatz |
| * 250 "/home/raddatz" is current directory. |
| * $ dir test* |
| * 227 Entering Passive Mode (10,200,36,33,200,189). |
| * 125 List started. |
| * RADDATZ 200 21.05.11 12:31:18 *STMF TEST_RG_02_CRLF.properties |
| * RADDATZ 187 08.05.11 12:31:40 *STMF TEST_RG_02_LF.properties |
| * RADDATZ 187 08.05.11 12:31:52 *STMF TEST_RG_02_CR.properties |
| * RADDATZ 8192 04.07.13 09:04:14 *DIR testDir1/ |
| * RADDATZ 8192 04.07.13 09:04:17 *DIR testDir2/ |
| * 250 List completed. |
| * |
| * |
| * Example 1, using ANT to list specific members of a file: |
| * -------------------------------------------------------- |
| * |
| * <echo/> |
| * <echo>Listing members of a file:</echo> |
| * |
| * <ftp action="list" |
| * server="${ftp.server}" |
| * userid="${ftp.user}" |
| * password="${ftp.password}" |
| * binary="false" |
| * verbose="true" |
| * remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE" |
| * systemTypeKey="OS/400" |
| * listing="ftp-listing.txt" |
| * > |
| * <fileset dir="./i5-downloads-file" casesensitive="false"> |
| * <include name="run*.mbr" /> |
| * </fileset> |
| * </ftp> |
| * |
| * Output: |
| * ------- |
| * |
| * [echo] Listing members of a file: |
| * [ftp] listing files |
| * [ftp] listing RUN.MBR |
| * [ftp] listing RUNNER.MBR |
| * [ftp] listing RUNNERBND.MBR |
| * [ftp] 3 files listed |
| * |
| * |
| * Example 2, using ANT to list specific members of all files of a library: |
| * ------------------------------------------------------------------------ |
| * |
| * <echo/> |
| * <echo>Listing members of all files of a library:</echo> |
| * |
| * <ftp action="list" |
| * server="${ftp.server}" |
| * userid="${ftp.user}" |
| * password="${ftp.password}" |
| * binary="false" |
| * verbose="true" |
| * remotedir="/QSYS.LIB/RPGUNIT.LIB" |
| * systemTypeKey="OS/400" |
| * listing="ftp-listing.txt" |
| * > |
| * <fileset dir="./i5-downloads-lib" casesensitive="false"> |
| * <include name="**\run*.mbr" /> |
| * </fileset> |
| * </ftp> |
| * |
| * Output: |
| * ------- |
| * |
| * [echo] Listing members of all files of a library: |
| * [ftp] listing files |
| * [ftp] listing RPGUNIT1.FILE\RUN.MBR |
| * [ftp] listing RPGUNIT1.FILE\RUNRMT.MBR |
| * [ftp] listing RPGUNITT1.FILE\RUNT.MBR |
| * [ftp] listing RPGUNITY1.FILE\RUN.MBR |
| * [ftp] listing RPGUNITY1.FILE\RUNNER.MBR |
| * [ftp] listing RPGUNITY1.FILE\RUNNERBND.MBR |
| * [ftp] 6 files listed |
| * |
| * |
| * Example 3, using ANT to download specific members of a file: |
| * ------------------------------------------------------------ |
| * |
| * <echo/> |
| * <echo>Downloading members of a file:</echo> |
| * |
| * <ftp action="get" |
| * server="${ftp.server}" |
| * userid="${ftp.user}" |
| * password="${ftp.password}" |
| * binary="false" |
| * verbose="true" |
| * remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE" |
| * systemTypeKey="OS/400" |
| * > |
| * <fileset dir="./i5-downloads-file" casesensitive="false"> |
| * <include name="run*.mbr" /> |
| * </fileset> |
| * </ftp> |
| * |
| * Output: |
| * ------- |
| * |
| * [echo] Downloading members of a file: |
| * [ftp] getting files |
| * [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUN.MBR |
| * [ftp] transferring RUNNER.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNER.MBR |
| * [ftp] transferring RUNNERBND.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNERBND.MBR |
| * [ftp] 3 files retrieved |
| * |
| * |
| * Example 4, using ANT to download specific members of all files of a library: |
| * ---------------------------------------------------------------------------- |
| * |
| * <echo/> |
| * <echo>Downloading members of all files of a library:</echo> |
| * |
| * <ftp action="get" |
| * server="${ftp.server}" |
| * userid="${ftp.user}" |
| * password="${ftp.password}" |
| * binary="false" |
| * verbose="true" |
| * remotedir="/QSYS.LIB/RPGUNIT.LIB" |
| * systemTypeKey="OS/400" |
| * > |
| * <fileset dir="./i5-downloads-lib" casesensitive="false"> |
| * <include name="**\run*.mbr" /> |
| * </fileset> |
| * </ftp> |
| * |
| * Output: |
| * ------- |
| * |
| * [echo] Downloading members of all files of a library: |
| * [ftp] getting files |
| * [ftp] transferring RPGUNIT1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNIT1.FILE\RUN.MBR |
| * [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR |
| * [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITT1.FILE\RUNT.MBR |
| * [ftp] transferring RPGUNITY1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUN.MBR |
| * [ftp] transferring RPGUNITY1.FILE\RUNNER.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNER.MBR |
| * [ftp] transferring RPGUNITY1.FILE\RUNNERBND.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNERBND.MBR |
| * [ftp] 6 files retrieved |
| * |
| * |
| * Example 5, using ANT to download a save file of a library: |
| * ---------------------------------------------------------- |
| * |
| * <ftp action="get" |
| * server="${ftp.server}" |
| * userid="${ftp.user}" |
| * password="${ftp.password}" |
| * binary="true" |
| * verbose="true" |
| * remotedir="/QSYS.LIB/RPGUNIT.LIB" |
| * systemTypeKey="OS/400" |
| * > |
| * <fileset dir="./i5-downloads-savf" casesensitive="false"> |
| * <include name="RPGUNIT.SAVF" /> |
| * </fileset> |
| * </ftp> |
| * |
| * Output: |
| * ------- |
| * [echo] Downloading save file: |
| * [ftp] getting files |
| * [ftp] transferring RPGUNIT.SAVF to C:\workspaces\rdp_080\workspace\net-Test\i5-downloads-lib\RPGUNIT.SAVF |
| * [ftp] 1 files retrieved |
| * |
| * </pre> |
| */ |
| public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl |
| { |
| private static final String DEFAULT_DATE_FORMAT |
| = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24 |
| |
| |
| |
| private static final String REGEX = |
| "(\\S+)\\s+" // user |
| + "(?:(\\d+)\\s+)?" // size, empty for members |
| + "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members |
| + "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM |
| + "(?:(\\S+)\\s*)?"; // file name, missing, when CWD is a *FILE |
| |
| |
| /** |
| * The default constructor for a OS400FTPEntryParser object. |
| * |
| * @throws IllegalArgumentException |
| * Thrown if the regular expression is unparseable. Should not be seen |
| * under normal conditions. It it is seen, this is a sign that |
| * <code>REGEX</code> is not a valid regular expression. |
| */ |
| public OS400FTPEntryParser() |
| { |
| this(null); |
| } |
| |
| /** |
| * This constructor allows the creation of an OS400FTPEntryParser object |
| * with something other than the default configuration. |
| * |
| * @param config The {@link FTPClientConfig configuration} object used to |
| * configure this parser. |
| * @throws IllegalArgumentException |
| * Thrown if the regular expression is unparseable. Should not be seen |
| * under normal conditions. It it is seen, this is a sign that |
| * <code>REGEX</code> is not a valid regular expression. |
| * @since 1.4 |
| */ |
| public OS400FTPEntryParser(final FTPClientConfig config) |
| { |
| super(REGEX); |
| configure(config); |
| } |
| |
| |
| /** |
| * Defines a default configuration to be used when this class is |
| * instantiated without a {@link FTPClientConfig FTPClientConfig} |
| * parameter being specified. |
| * @return the default configuration for this parser. |
| */ |
| @Override |
| protected FTPClientConfig getDefaultConfiguration() { |
| return new FTPClientConfig( |
| FTPClientConfig.SYST_OS400, |
| DEFAULT_DATE_FORMAT, |
| null); |
| } |
| |
| /** |
| * |
| * @param string String value that is checked for <code>null</code> |
| * or empty. |
| * @return <code>true</code> for <code>null</code> or empty values, |
| * else <code>false</code>. |
| */ |
| private boolean isNullOrEmpty(final String string) { |
| if (string == null || string.isEmpty()) { |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public FTPFile parseFTPEntry(final String entry) |
| { |
| |
| final FTPFile file = new FTPFile(); |
| file.setRawListing(entry); |
| final int type; |
| |
| if (matches(entry)) |
| { |
| final String usr = group(1); |
| final String filesize = group(2); |
| String datestr = ""; |
| if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) |
| { |
| datestr = group(3)+" "+group(4); |
| } |
| final String typeStr = group(5); |
| String name = group(6); |
| |
| boolean mustScanForPathSeparator = true; |
| |
| try |
| { |
| file.setTimestamp(super.parseTimestamp(datestr)); |
| } |
| catch (final ParseException e) |
| { |
| // intentionally do nothing |
| } |
| |
| |
| if (typeStr.equalsIgnoreCase("*STMF")) |
| { |
| type = FTPFile.FILE_TYPE; |
| if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) |
| { |
| return null; |
| } |
| } |
| else if (typeStr.equalsIgnoreCase("*DIR")) |
| { |
| type = FTPFile.DIRECTORY_TYPE; |
| if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) |
| { |
| return null; |
| } |
| } |
| else if (typeStr.equalsIgnoreCase("*FILE")) |
| { |
| // File, defines the structure of the data (columns of a row) |
| // but the data is stored in one or more members. Typically a |
| // source file contains multiple members whereas it is |
| // recommended (but not enforced) to use one member per data |
| // file. |
| // Save files are a special type of files which are used |
| // to save objects, e.g. for backups. |
| if ((name == null) || !name.toUpperCase(Locale.ROOT).endsWith(".SAVF")) { |
| return null; |
| } |
| mustScanForPathSeparator = false; |
| type = FTPFile.FILE_TYPE; |
| } |
| else if (typeStr.equalsIgnoreCase("*MEM")) |
| { |
| mustScanForPathSeparator = false; |
| type = FTPFile.FILE_TYPE; |
| |
| if (isNullOrEmpty(name)) |
| { |
| return null; |
| } |
| if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) |
| { |
| return null; |
| } |
| |
| // Quick and dirty bug fix to make SelectorUtils work. |
| // Class SelectorUtils uses 'File.separator' to splitt |
| // a given path into pieces. But actually it had to |
| // use the separator of the FTP server, which is a forward |
| // slash in case of an AS/400. |
| name = name.replace('/', File.separatorChar); |
| } |
| else |
| { |
| type = FTPFile.UNKNOWN_TYPE; |
| } |
| |
| file.setType(type); |
| |
| file.setUser(usr); |
| |
| try |
| { |
| file.setSize(Long.parseLong(filesize)); |
| } |
| catch (final NumberFormatException e) |
| { |
| // intentionally do nothing |
| } |
| |
| if (name.endsWith("/")) |
| { |
| name = name.substring(0, name.length() - 1); |
| } |
| if (mustScanForPathSeparator) |
| { |
| final int pos = name.lastIndexOf('/'); |
| if (pos > -1) |
| { |
| name = name.substring(pos + 1); |
| } |
| } |
| |
| file.setName(name); |
| |
| return file; |
| } |
| return null; |
| } |
| |
| } |