    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.net.ftp.parser;
    019
    020    import java.util.HashMap;
    021    import java.util.List;
    022    import java.util.ListIterator;
    023    import java.util.regex.MatchResult;
    024    import java.util.regex.Matcher;
    025    import java.util.regex.Pattern;
    026    import java.util.regex.PatternSyntaxException;
    027
    028    import org.apache.commons.net.ftp.FTPClientConfig;
    029
    030    /**
    031     * Special implementation VMSFTPEntryParser with versioning turned on.
    032     * This parser removes all duplicates and only leaves the version with the highest
    033     * version number for each filename.
    034     *
    035     * This is a sample of VMS LIST output
    036     *
    037     *  "1-JUN.LIS;1              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
    038     *  "1-JUN.LIS;2              9/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
    039     *  "DATA.DIR;1               1/9           2-JUN-1998 07:32:04  [GROUP,OWNER]    (RWED,RWED,RWED,RE)",
    040     * <P>
    041     *
    042     * @author  <a href="Winston.Ojeda@qg.com">Winston Ojeda</a>
    043     * @author <a href="sestegra@free.fr">Stephane ESTE-GRACIAS</a>
    044     * @version $Id: VMSVersioningFTPEntryParser.java 999923 2010-09-22 13:03:51Z sebb $
    045     *
    046     * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
    047     */
    048    public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
    049    {
    050
    051        private final Pattern _preparse_pattern_;
    052        private static final String PRE_PARSE_REGEX =
    053            "(.*);([0-9]+)\\s*.*";
    054
    055        /**
    056         * Constructor for a VMSFTPEntryParser object.
    057         *
    058         * @exception IllegalArgumentException
    059         * Thrown if the regular expression is unparseable.  Should not be seen
    060         * under normal conditions.  It it is seen, this is a sign that
    061         * <code>REGEX</code> is  not a valid regular expression.
    062         */
    063        public VMSVersioningFTPEntryParser()
    064        {
    065            this(null);
    066        }
    067
    068        /**
    069         * This constructor allows the creation of a VMSVersioningFTPEntryParser
    070         * object with something other than the default configuration.
    071         *
    072         * @param config The {@link FTPClientConfig configuration} object used to
    073         * configure this parser.
    074         * @exception IllegalArgumentException
    075         * Thrown if the regular expression is unparseable.  Should not be seen
    076         * under normal conditions.  It it is seen, this is a sign that
    077         * <code>REGEX</code> is  not a valid regular expression.
    078         * @since 1.4
    079         */
    080        public VMSVersioningFTPEntryParser(FTPClientConfig config)
    081        {
    082            super();
    083            configure(config);
    084            try
    085            {
    086                //_preparse_matcher_ = new Perl5Matcher();
    087                _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX);
    088            }
    089            catch (PatternSyntaxException pse)
    090            {
    091                throw new IllegalArgumentException (
    092                    "Unparseable regex supplied:  " + PRE_PARSE_REGEX);
    093            }
    094
    095       }
    096
    097        /**
    098         * Implement hook provided for those implementers (such as
    099         * VMSVersioningFTPEntryParser, and possibly others) which return
    100         * multiple files with the same name to remove the duplicates ..
    101         *
    102         * @param original Original list
    103         *
    104         * @return Original list purged of duplicates
    105         */
    106        @Override
    107        public List<String> preParse(List<String> original) {
    108            original = super.preParse(original);
    109            HashMap<String, Integer> existingEntries = new HashMap<String, Integer>();
    110            ListIterator<String> iter = original.listIterator();
    111            while (iter.hasNext()) {
    112                String entry = iter.next().trim();
    113                MatchResult result = null;
    114                Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry);
    115                if (_preparse_matcher_.matches()) {
    116                    result = _preparse_matcher_.toMatchResult();
    117                    String name = result.group(1);
    118                    String version = result.group(2);
    119                    Integer nv = Integer.valueOf(version);
    120                    Integer existing = existingEntries.get(name);
    121                    if (null != existing) {
    122                        if (nv.intValue() < existing.intValue()) {
    123                            iter.remove();  // removes older version from original list.
    124                            continue;
    125                        }
    126                    }
    127                    existingEntries.put(name, nv);
    128                }
    129
    130            }
    131            // we've now removed all entries less than with less than the largest
    132            // version number for each name that were listed after the largest.
    133            // we now must remove those with smaller than the largest version number
    134            // for each name that were found before the largest
    135            while (iter.hasPrevious()) {
    136                String entry = iter.previous().trim();
    137                MatchResult result = null;
    138                Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry);
    139                if (_preparse_matcher_.matches()) {
    140                    result = _preparse_matcher_.toMatchResult();
    141                    String name = result.group(1);
    142                    String version = result.group(2);
    143                    Integer nv = Integer.valueOf(version);
    144                    Integer existing = existingEntries.get(name);
    145                    if (null != existing) {
    146                        if (nv.intValue() < existing.intValue()) {
    147                            iter.remove(); // removes older version from original list.
    148                        }
    149                    }
    150                }
    151
    152            }
    153            return original;
    154        }
    155
    156
    157        @Override
    158        protected boolean isVersioning() {
    159            return true;
    160        }
    161
    162    }
    163
    164    /* Emacs configuration
    165     * Local variables:        **
    166     * mode:             java  **
    167     * c-basic-offset:   4     **
    168     * indent-tabs-mode: nil   **
    169     * End:                    **
    170     */