View Javadoc
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 }