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