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