1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.ftp.parser;
19
20 import java.util.regex.MatchResult;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23 import java.util.regex.PatternSyntaxException;
24
25 import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
26
27 /**
28 * This abstract class implements both the older FTPFileListParser and newer FTPFileEntryParser interfaces with default functionality. All the classes in the
29 * parser subpackage inherit from this.
30 * <p>
31 * This is the base class for all regular expression based FTPFileEntryParser classes
32 * </p>
33 */
34 public abstract class RegexFTPFileEntryParserImpl extends FTPFileEntryParserImpl {
35 /**
36 * Internal pattern the matcher tries to match, representing a file entry
37 */
38 private Pattern pattern;
39
40 /**
41 * Internal match result used by the parser
42 */
43 private MatchResult result;
44
45 /**
46 * Internal PatternMatcher object used by the parser. It has protected scope in case subclasses want to make use of it for their own purposes.
47 */
48 protected Matcher _matcher_;
49
50 /**
51 * The constructor for a RegexFTPFileEntryParserImpl object. The expression is compiled with flags = 0.
52 *
53 * @param regex The regular expression with which this object is initialized.
54 * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen in normal conditions. If it is seen, this is a sign
55 * that a subclass has been created with a bad regular expression. Since the parser must be created before use, this means
56 * that any bad parser subclasses created from this will bomb very quickly, leading to easy detection.
57 */
58
59 public RegexFTPFileEntryParserImpl(final String regex) {
60 compileRegex(regex, 0);
61 }
62
63 /**
64 * The constructor for a RegexFTPFileEntryParserImpl object.
65 *
66 * @param regex The regular expression with which this object is initialized.
67 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
68 * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen in normal conditions. If it is seen, this is a sign
69 * that a subclass has been created with a bad regular expression. Since the parser must be created before use, this means
70 * that any bad parser subclasses created from this will bomb very quickly, leading to easy detection.
71 * @since 3.4
72 */
73 public RegexFTPFileEntryParserImpl(final String regex, final int flags) {
74 compileRegex(regex, flags);
75 }
76
77 /**
78 * Compile the regex and store the {@link Pattern}.
79 *
80 * This is an internal method to do the work so the constructor does not have to call an overrideable method.
81 *
82 * @param regex the expression to compile
83 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
84 * @throws IllegalArgumentException if the regex cannot be compiled
85 */
86 private void compileRegex(final String regex, final int flags) {
87 try {
88 pattern = Pattern.compile(regex, flags);
89 } catch (final PatternSyntaxException pse) {
90 throw new IllegalArgumentException("Unparseable regex supplied: " + regex);
91 }
92 }
93
94 /**
95 * Convenience method
96 *
97 * @return the number of groups() in the internal MatchResult.
98 */
99 public int getGroupCnt() {
100 if (result == null) {
101 return 0;
102 }
103 return result.groupCount();
104 }
105
106 /**
107 * Gets a string shows each match group by number.
108 * <p>
109 * For debugging purposes.
110 * </p>
111 *
112 * @return a string shows each match group by number.
113 */
114 public String getGroupsAsString() {
115 final StringBuilder b = new StringBuilder();
116 for (int i = 1; i <= result.groupCount(); i++) {
117 b.append(i).append(") ").append(result.group(i)).append(System.lineSeparator());
118 }
119 return b.toString();
120 }
121
122 /**
123 * Convenience method delegates to the internal MatchResult's group() method.
124 *
125 * @param matchNum match group number to be retrieved
126 * @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.
127 */
128 public String group(final int matchNum) {
129 if (result == null) {
130 return null;
131 }
132 return result.group(matchNum);
133 }
134
135 /**
136 * Convenience method delegates to the internal MatchResult's matches() method.
137 *
138 * @param s the String to be matched
139 * @return true if s matches this object's regular expression.
140 */
141 public boolean matches(final String s) {
142 result = null;
143 _matcher_ = pattern.matcher(s);
144 if (_matcher_.matches()) {
145 result = _matcher_.toMatchResult();
146 }
147 return null != result;
148 }
149
150 /**
151 * Sets the regular expression for entry parsing and create a new {@link Pattern} instance.
152 *
153 * @param regex The new regular expression
154 * @return true
155 * @throws IllegalArgumentException if the regex cannot be compiled
156 * @since 2.0
157 */
158 public boolean setRegex(final String regex) {
159 compileRegex(regex, 0);
160 return true;
161 }
162
163 /**
164 * Sets the regular expression for entry parsing and create a new {@link Pattern} instance.
165 *
166 * @param regex The new regular expression
167 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
168 * @return true
169 * @throws IllegalArgumentException if the regex cannot be compiled
170 * @since 3.4
171 */
172 public boolean setRegex(final String regex, final int flags) {
173 compileRegex(regex, flags);
174 return true;
175 }
176 }