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       * 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 }