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