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: private Perl5Matcher _preparse_matcher_;
050: private Pattern _preparse_pattern_;
051: private static final String PRE_PARSE_REGEX = "(.*);([0-9]+)\\s*.*";
052:
053: /**
054: * Constructor for a VMSFTPEntryParser object. Sets the versioning member
055: * to the supplied value.
056: *
057: * @exception IllegalArgumentException
058: * Thrown if the regular expression is unparseable. Should not be seen
059: * under normal conditions. It it is seen, this is a sign that
060: * <code>REGEX</code> is not a valid regular expression.
061: */
062: public VMSVersioningFTPEntryParser() {
063: this (null);
064: }
065:
066: /**
067: * This constructor allows the creation of a VMSVersioningFTPEntryParser
068: * object with something other than the default configuration.
069: *
070: * @param config The {@link FTPClientConfig configuration} object used to
071: * configure this parser.
072: * @exception IllegalArgumentException
073: * Thrown if the regular expression is unparseable. Should not be seen
074: * under normal conditions. It it is seen, this is a sign that
075: * <code>REGEX</code> is not a valid regular expression.
076: * @since 1.4
077: */
078: public VMSVersioningFTPEntryParser(FTPClientConfig config) {
079: super ();
080: configure(config);
081: try {
082: _preparse_matcher_ = new Perl5Matcher();
083: _preparse_pattern_ = new Perl5Compiler()
084: .compile(PRE_PARSE_REGEX);
085: } catch (MalformedPatternException e) {
086: throw new IllegalArgumentException(
087: "Unparseable regex supplied: " + PRE_PARSE_REGEX);
088: }
089:
090: }
091:
092: private class NameVersion {
093: String name;
094: int versionNumber;
095:
096: NameVersion(String name, String vers) {
097: this .name = name;
098: this .versionNumber = Integer.parseInt(vers);
099: }
100: }
101:
102: /**
103: * Implement hook provided for those implementers (such as
104: * VMSVersioningFTPEntryParser, and possibly others) which return
105: * multiple files with the same name to remove the duplicates ..
106: *
107: * @param original Original list
108: *
109: * @return Original list purged of duplicates
110: */
111: public List preParse(List original) {
112: original = super .preParse(original);
113: HashMap existingEntries = new HashMap();
114: ListIterator iter = original.listIterator();
115: while (iter.hasNext()) {
116: String entry = ((String) iter.next()).trim();
117: MatchResult result = null;
118: if (_preparse_matcher_.matches(entry, _preparse_pattern_)) {
119: result = _preparse_matcher_.getMatch();
120: String name = result.group(1);
121: String version = result.group(2);
122: NameVersion nv = new NameVersion(name, version);
123: NameVersion existing = (NameVersion) existingEntries
124: .get(name);
125: if (null != existing) {
126: if (nv.versionNumber < existing.versionNumber) {
127: iter.remove(); // removal removes from original list.
128: continue;
129: }
130: }
131: existingEntries.put(name, nv);
132: }
133:
134: }
135: // we've now removed all entries less than with less than the largest
136: // version number for each name that were listed after the largest.
137: // we now must remove those with smaller than the largest version number
138: // for each name that were found before the largest
139: while (iter.hasPrevious()) {
140: String entry = ((String) iter.previous()).trim();
141: MatchResult result = null;
142: if (_preparse_matcher_.matches(entry, _preparse_pattern_)) {
143: result = _preparse_matcher_.getMatch();
144: String name = result.group(1);
145: String version = result.group(2);
146: NameVersion nv = new NameVersion(name, version);
147: NameVersion existing = (NameVersion) existingEntries
148: .get(name);
149: if (null != existing) {
150: if (nv.versionNumber < existing.versionNumber) {
151: iter.remove(); // removal removes from original list.
152: }
153: }
154: }
155:
156: }
157: return original;
158: }
159:
160: protected boolean isVersioning() {
161: return true;
162: }
163:
164: }
165:
166: /* Emacs configuration
167: * Local variables: **
168: * mode: java **
169: * c-basic-offset: 4 **
170: * indent-tabs-mode: nil **
171: * End: **
172: */
|