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 /**
37 * Internal pattern the matcher tries to match, representing a file entry
38 */
39 private Pattern pattern;
40
41 /**
42 * Internal match result used by the parser
43 */
44 private MatchResult result;
45
46 /**
47 * Internal PatternMatcher object used by the parser. It has protected scope in case subclasses want to make use of it for their own purposes.
48 */
49 protected Matcher _matcher_;
50
51 /**
52 * The constructor for a RegexFTPFileEntryParserImpl object. The expression is compiled with flags = 0.
53 *
54 * @param regex The regular expression with which this object is initialized.
55 * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen in normal conditions. If it is seen, this is a sign
56 * that a subclass has been created with a bad regular expression. Since the parser must be created before use, this means
57 * that any bad parser subclasses created from this will bomb very quickly, leading to easy detection.
58 */
59
60 public RegexFTPFileEntryParserImpl(final String regex) {
61 compileRegex(regex, 0);
62 }
63
64 /**
65 * The constructor for a RegexFTPFileEntryParserImpl object.
66 *
67 * @param regex The regular expression with which this object is initialized.
68 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
69 * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not be seen in normal conditions. If it is seen, this is a sign
70 * that a subclass has been created with a bad regular expression. Since the parser must be created before use, this means
71 * that any bad parser subclasses created from this will bomb very quickly, leading to easy detection.
72 * @since 3.4
73 */
74 public RegexFTPFileEntryParserImpl(final String regex, final int flags) {
75 compileRegex(regex, flags);
76 }
77
78 /**
79 * Compile the regex and store the {@link Pattern}.
80 *
81 * This is an internal method to do the work so the constructor does not have to call an overrideable method.
82 *
83 * @param regex the expression to compile
84 * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
85 * @throws IllegalArgumentException if the regex cannot be compiled
86 */
87 private void compileRegex(final String regex, final int flags) {
88 try {
89 pattern = Pattern.compile(regex, flags);
90 } catch (final PatternSyntaxException pse) {
91 throw new IllegalArgumentException("Unparseable regex supplied: " + regex);
92 }
93 }
94
95 /**
96 * Convenience method
97 *
98 * @return the number of groups() in the internal MatchResult.
99 */
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 }