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 1299238 2012-03-10 17:12:28Z 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 HashMap<String, Integer> existingEntries = new HashMap<String, Integer>(); 109 ListIterator<String> iter = original.listIterator(); 110 while (iter.hasNext()) { 111 String entry = iter.next().trim(); 112 MatchResult result = null; 113 Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); 114 if (_preparse_matcher_.matches()) { 115 result = _preparse_matcher_.toMatchResult(); 116 String name = result.group(1); 117 String version = result.group(2); 118 Integer nv = Integer.valueOf(version); 119 Integer existing = existingEntries.get(name); 120 if (null != existing) { 121 if (nv.intValue() < existing.intValue()) { 122 iter.remove(); // removes older version from original list. 123 continue; 124 } 125 } 126 existingEntries.put(name, nv); 127 } 128 129 } 130 // we've now removed all entries less than with less than the largest 131 // version number for each name that were listed after the largest. 132 // we now must remove those with smaller than the largest version number 133 // for each name that were found before the largest 134 while (iter.hasPrevious()) { 135 String entry = iter.previous().trim(); 136 MatchResult result = null; 137 Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); 138 if (_preparse_matcher_.matches()) { 139 result = _preparse_matcher_.toMatchResult(); 140 String name = result.group(1); 141 String version = result.group(2); 142 Integer nv = Integer.valueOf(version); 143 Integer existing = existingEntries.get(name); 144 if (null != existing) { 145 if (nv.intValue() < existing.intValue()) { 146 iter.remove(); // removes older version from original list. 147 } 148 } 149 } 150 151 } 152 return original; 153 } 154 155 156 @Override 157 protected boolean isVersioning() { 158 return true; 159 } 160 161 } 162 163 /* Emacs configuration 164 * Local variables: ** 165 * mode: java ** 166 * c-basic-offset: 4 ** 167 * indent-tabs-mode: nil ** 168 * End: ** 169 */