OS400FTPEntryParser.java
- /*
- * 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. If 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. If 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} or empty.
- * @return {@code true} for {@code null} or empty values, else {@code false}.
- */
- private boolean isNullOrEmpty(final String string) {
- return string == null || string.isEmpty();
- }
- @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;
- }
- }