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 018package org.apache.commons.net.ftp.parser; 019 020import java.util.HashMap; 021import java.util.List; 022import java.util.ListIterator; 023import java.util.regex.MatchResult; 024import java.util.regex.Matcher; 025import java.util.regex.Pattern; 026import java.util.regex.PatternSyntaxException; 027 028import 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 * @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ 043 * 044 * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) 045 */ 046public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser 047{ 048 049 private final Pattern _preparse_pattern_; 050 private static final String PRE_PARSE_REGEX = 051 "(.*?);([0-9]+)\\s*.*"; 052 053 /** 054 * Constructor for a VMSFTPEntryParser object. 055 * 056 * @throws IllegalArgumentException 057 * Thrown if the regular expression is unparseable. Should not be seen 058 * under normal conditions. It it is seen, this is a sign that 059 * <code>REGEX</code> is not a valid regular expression. 060 */ 061 public VMSVersioningFTPEntryParser() 062 { 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 * @throws 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 { 080 super(); 081 configure(config); 082 try 083 { 084 //_preparse_matcher_ = new Perl5Matcher(); 085 _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); 086 } 087 catch (PatternSyntaxException pse) 088 { 089 throw new IllegalArgumentException ( 090 "Unparseable regex supplied: " + PRE_PARSE_REGEX); 091 } 092 093 } 094 095 /** 096 * Implement hook provided for those implementers (such as 097 * VMSVersioningFTPEntryParser, and possibly others) which return 098 * multiple files with the same name to remove the duplicates .. 099 * 100 * @param original Original list 101 * 102 * @return Original list purged of duplicates 103 */ 104 @Override 105 public List<String> preParse(List<String> original) { 106 HashMap<String, Integer> existingEntries = new HashMap<String, Integer>(); 107 ListIterator<String> iter = original.listIterator(); 108 while (iter.hasNext()) { 109 String entry = iter.next().trim(); 110 MatchResult result = null; 111 Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); 112 if (_preparse_matcher_.matches()) { 113 result = _preparse_matcher_.toMatchResult(); 114 String name = result.group(1); 115 String version = result.group(2); 116 Integer nv = Integer.valueOf(version); 117 Integer existing = existingEntries.get(name); 118 if (null != existing) { 119 if (nv.intValue() < existing.intValue()) { 120 iter.remove(); // removes older version from original list. 121 continue; 122 } 123 } 124 existingEntries.put(name, nv); 125 } 126 127 } 128 // we've now removed all entries less than with less than the largest 129 // version number for each name that were listed after the largest. 130 // we now must remove those with smaller than the largest version number 131 // for each name that were found before the largest 132 while (iter.hasPrevious()) { 133 String entry = iter.previous().trim(); 134 MatchResult result = null; 135 Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); 136 if (_preparse_matcher_.matches()) { 137 result = _preparse_matcher_.toMatchResult(); 138 String name = result.group(1); 139 String version = result.group(2); 140 Integer nv = Integer.valueOf(version); 141 Integer existing = existingEntries.get(name); 142 if (null != existing) { 143 if (nv.intValue() < existing.intValue()) { 144 iter.remove(); // removes older version from original list. 145 } 146 } 147 } 148 149 } 150 return original; 151 } 152 153 154 @Override 155 protected boolean isVersioning() { 156 return true; 157 } 158 159} 160 161/* Emacs configuration 162 * Local variables: ** 163 * mode: java ** 164 * c-basic-offset: 4 ** 165 * indent-tabs-mode: nil ** 166 * End: ** 167 */