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 019package org.apache.commons.net.ftp.parser; 020 021import java.util.regex.MatchResult; 022import java.util.regex.Matcher; 023import java.util.regex.Pattern; 024import java.util.regex.PatternSyntaxException; 025 026import org.apache.commons.net.ftp.FTPFileEntryParserImpl; 027 028/** 029 * This abstract class implements both the older FTPFileListParser and 030 * newer FTPFileEntryParser interfaces with default functionality. 031 * All the classes in the parser subpackage inherit from this. 032 * 033 * This is the base class for all regular expression based FTPFileEntryParser classes 034 */ 035public abstract class RegexFTPFileEntryParserImpl extends 036 FTPFileEntryParserImpl { 037 /** 038 * internal pattern the matcher tries to match, representing a file 039 * entry 040 */ 041 private Pattern pattern; 042 043 /** 044 * internal match result used by the parser 045 */ 046 private MatchResult result; 047 048 /** 049 * Internal PatternMatcher object used by the parser. It has protected 050 * scope in case subclasses want to make use of it for their own purposes. 051 */ 052 protected Matcher _matcher_; 053 054 /** 055 * The constructor for a RegexFTPFileEntryParserImpl object. 056 * The expression is compiled with flags = 0. 057 * 058 * @param regex The regular expression with which this object is 059 * initialized. 060 * 061 * @throws IllegalArgumentException 062 * Thrown if the regular expression is unparseable. Should not be seen in 063 * normal conditions. It it is seen, this is a sign that a subclass has 064 * been created with a bad regular expression. Since the parser must be 065 * created before use, this means that any bad parser subclasses created 066 * from this will bomb very quickly, leading to easy detection. 067 */ 068 069 public RegexFTPFileEntryParserImpl(final String regex) { 070 compileRegex(regex, 0); 071 } 072 073 /** 074 * The constructor for a RegexFTPFileEntryParserImpl object. 075 * 076 * @param regex The regular expression with which this object is 077 * initialized. 078 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. 079 * 080 * @throws IllegalArgumentException 081 * Thrown if the regular expression is unparseable. Should not be seen in 082 * normal conditions. It it is seen, this is a sign that a subclass has 083 * been created with a bad regular expression. Since the parser must be 084 * created before use, this means that any bad parser subclasses created 085 * from this will bomb very quickly, leading to easy detection. 086 * @since 3.4 087 */ 088 public RegexFTPFileEntryParserImpl(final String regex, final int flags) { 089 compileRegex(regex, flags); 090 } 091 092 /** 093 * Convenience method delegates to the internal MatchResult's matches() 094 * method. 095 * 096 * @param s the String to be matched 097 * @return true if s matches this object's regular expression. 098 */ 099 100 public boolean matches(final String s) { 101 this.result = null; 102 _matcher_ = pattern.matcher(s); 103 if (_matcher_.matches()) { 104 this.result = _matcher_.toMatchResult(); 105 } 106 return null != this.result; 107 } 108 109 /** 110 * Convenience method 111 * 112 * @return the number of groups() in the internal MatchResult. 113 */ 114 115 public int getGroupCnt() { 116 if (this.result == null) { 117 return 0; 118 } 119 return this.result.groupCount(); 120 } 121 122 /** 123 * Convenience method delegates to the internal MatchResult's group() 124 * method. 125 * 126 * @param matchnum match group number to be retrieved 127 * 128 * @return the content of the <code>matchnum'th</code> group of the internal 129 * match or null if this method is called without a match having 130 * been made. 131 */ 132 public String group(final int matchnum) { 133 if (this.result == null) { 134 return null; 135 } 136 return this.result.group(matchnum); 137 } 138 139 /** 140 * For debugging purposes - returns a string shows each match group by 141 * number. 142 * 143 * @return a string shows each match group by number. 144 */ 145 146 public String getGroupsAsString() { 147 final StringBuilder b = new StringBuilder(); 148 for (int i = 1; i <= this.result.groupCount(); i++) { 149 b.append(i).append(") ").append(this.result.group(i)).append( 150 System.getProperty("line.separator")); 151 } 152 return b.toString(); 153 } 154 155 /** 156 * Alter the current regular expression being utilised for entry parsing 157 * and create a new {@link Pattern} instance. 158 * @param regex The new regular expression 159 * @return true 160 * @since 2.0 161 * @throws IllegalArgumentException if the regex cannot be compiled 162 */ 163 public boolean setRegex(final String regex) { 164 compileRegex(regex, 0); 165 return true; 166 } 167 168 169 /** 170 * Alter the current regular expression being utilised for entry parsing 171 * and create a new {@link Pattern} instance. 172 * @param regex The new regular expression 173 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. 174 * @return true 175 * @since 3.4 176 * @throws IllegalArgumentException if the regex cannot be compiled 177 */ 178 public boolean setRegex(final String regex, final int flags) { 179 compileRegex(regex, flags); 180 return true; 181 } 182 183 /** 184 * Compile the regex and store the {@link Pattern}. 185 * 186 * This is an internal method to do the work so the constructor does not 187 * have to call an overrideable method. 188 * 189 * @param regex the expression to compile 190 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. 191 * @throws IllegalArgumentException if the regex cannot be compiled 192 */ 193 private void compileRegex(final String regex, final int flags) { 194 try { 195 pattern = Pattern.compile(regex, flags); 196 } catch (final PatternSyntaxException pse) { 197 throw new IllegalArgumentException("Unparseable regex supplied: " + regex); 198 } 199 } 200}