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 */