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    *      http://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  package org.apache.logging.log4j.core.lookup;
18  
19  import java.util.Arrays;
20  
21  import org.apache.logging.log4j.util.Strings;
22  
23  /**
24   * A matcher class that can be queried to determine if a character array
25   * portion matches.
26   * <p>
27   * This class comes complete with various factory methods.
28   * If these do not suffice, you can subclass and implement your own matcher.
29   */
30  public abstract class StrMatcher {
31  
32      /**
33       * Matches the comma character.
34       */
35      private static final StrMatcher COMMA_MATCHER = new CharMatcher(',');
36      /**
37       * Matches the tab character.
38       */
39      private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
40      /**
41       * Matches the space character.
42       */
43      private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
44      /**
45       * Matches the same characters as StringTokenizer,
46       * namely space, tab, newline, formfeed.
47       */
48      private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray());
49      /**
50       * Matches the String trim() whitespace characters.
51       */
52      private static final StrMatcher TRIM_MATCHER = new TrimMatcher();
53      /**
54       * Matches the double quote character.
55       */
56      private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
57      /**
58       * Matches the double quote character.
59       */
60      private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
61      /**
62       * Matches the single or double quote character.
63       */
64      private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray());
65      /**
66       * Matches no characters.
67       */
68      private static final StrMatcher NONE_MATCHER = new NoMatcher();
69  
70      /**
71       * Constructor.
72       */
73      protected StrMatcher() {
74      }
75  
76      /**
77       * Returns a matcher which matches the comma character.
78       *
79       * @return a matcher for a comma
80       */
81      public static StrMatcher commaMatcher() {
82          return COMMA_MATCHER;
83      }
84  
85      /**
86       * Returns a matcher which matches the tab character.
87       *
88       * @return a matcher for a tab
89       */
90      public static StrMatcher tabMatcher() {
91          return TAB_MATCHER;
92      }
93  
94      /**
95       * Returns a matcher which matches the space character.
96       *
97       * @return a matcher for a space
98       */
99      public static StrMatcher spaceMatcher() {
100         return SPACE_MATCHER;
101     }
102 
103     /**
104      * Matches the same characters as StringTokenizer,
105      * namely space, tab, newline and formfeed.
106      *
107      * @return the split matcher
108      */
109     public static StrMatcher splitMatcher() {
110         return SPLIT_MATCHER;
111     }
112 
113     /**
114      * Matches the String trim() whitespace characters.
115      *
116      * @return the trim matcher
117      */
118     public static StrMatcher trimMatcher() {
119         return TRIM_MATCHER;
120     }
121 
122     /**
123      * Returns a matcher which matches the single quote character.
124      *
125      * @return a matcher for a single quote
126      */
127     public static StrMatcher singleQuoteMatcher() {
128         return SINGLE_QUOTE_MATCHER;
129     }
130 
131     /**
132      * Returns a matcher which matches the double quote character.
133      *
134      * @return a matcher for a double quote
135      */
136     public static StrMatcher doubleQuoteMatcher() {
137         return DOUBLE_QUOTE_MATCHER;
138     }
139 
140     /**
141      * Returns a matcher which matches the single or double quote character.
142      *
143      * @return a matcher for a single or double quote
144      */
145     public static StrMatcher quoteMatcher() {
146         return QUOTE_MATCHER;
147     }
148 
149     /**
150      * Matches no characters.
151      *
152      * @return a matcher that matches nothing
153      */
154     public static StrMatcher noneMatcher() {
155         return NONE_MATCHER;
156     }
157 
158     /**
159      * Constructor that creates a matcher from a character.
160      *
161      * @param ch  the character to match, must not be null
162      * @return a new Matcher for the given char
163      */
164     public static StrMatcher charMatcher(final char ch) {
165         return new CharMatcher(ch);
166     }
167 
168     /**
169      * Constructor that creates a matcher from a set of characters.
170      *
171      * @param chars  the characters to match, null or empty matches nothing
172      * @return a new matcher for the given char[]
173      */
174     public static StrMatcher charSetMatcher(final char[] chars) {
175         if (chars == null || chars.length == 0) {
176             return NONE_MATCHER;
177         }
178         if (chars.length == 1) {
179             return new CharMatcher(chars[0]);
180         }
181         return new CharSetMatcher(chars);
182     }
183 
184     /**
185      * Constructor that creates a matcher from a string representing a set of characters.
186      *
187      * @param chars  the characters to match, null or empty matches nothing
188      * @return a new Matcher for the given characters
189      */
190     public static StrMatcher charSetMatcher(final String chars) {
191         if (Strings.isEmpty(chars)) {
192             return NONE_MATCHER;
193         }
194         if (chars.length() == 1) {
195             return new CharMatcher(chars.charAt(0));
196         }
197         return new CharSetMatcher(chars.toCharArray());
198     }
199 
200     /**
201      * Constructor that creates a matcher from a string.
202      *
203      * @param str  the string to match, null or empty matches nothing
204      * @return a new Matcher for the given String
205      */
206     public static StrMatcher stringMatcher(final String str) {
207         if (Strings.isEmpty(str)) {
208             return NONE_MATCHER;
209         }
210         return new StringMatcher(str);
211     }
212 
213     /**
214      * Returns the number of matching characters, zero for no match.
215      * <p>
216      * This method is called to check for a match.
217      * The parameter <code>pos</code> represents the current position to be
218      * checked in the string <code>buffer</code> (a character array which must
219      * not be changed).
220      * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
221      * <p>
222      * The character array may be larger than the active area to be matched.
223      * Only values in the buffer between the specified indices may be accessed.
224      * <p>
225      * The matching code may check one character or many.
226      * It may check characters preceding <code>pos</code> as well as those
227      * after, so long as no checks exceed the bounds specified.
228      * <p>
229      * It must return zero for no match, or a positive number if a match was found.
230      * The number indicates the number of characters that matched.
231      *
232      * @param buffer  the text content to match against, do not change
233      * @param pos  the starting position for the match, valid for buffer
234      * @param bufferStart  the first active index in the buffer, valid for buffer
235      * @param bufferEnd  the end index (exclusive) of the active buffer, valid for buffer
236      * @return the number of matching characters, zero for no match
237      */
238     public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
239 
240     /**
241      * Returns the number of matching characters, zero for no match.
242      * <p>
243      * This method is called to check for a match.
244      * The parameter <code>pos</code> represents the current position to be
245      * checked in the string <code>buffer</code> (a character array which must
246      * not be changed).
247      * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
248      * <p>
249      * The matching code may check one character or many.
250      * It may check characters preceding <code>pos</code> as well as those after.
251      * <p>
252      * It must return zero for no match, or a positive number if a match was found.
253      * The number indicates the number of characters that matched.
254      *
255      * @param buffer  the text content to match against, do not change
256      * @param pos  the starting position for the match, valid for buffer
257      * @return the number of matching characters, zero for no match
258      * @since 2.4
259      */
260     public int isMatch(final char[] buffer, final int pos) {
261         return isMatch(buffer, pos, 0, buffer.length);
262     }
263 
264     //-----------------------------------------------------------------------
265     /**
266      * Class used to define a set of characters for matching purposes.
267      */
268     static final class CharSetMatcher extends StrMatcher {
269         /** The set of characters to match. */
270         private final char[] chars;
271 
272         /**
273          * Constructor that creates a matcher from a character array.
274          *
275          * @param chars  the characters to match, must not be null
276          */
277         CharSetMatcher(final char[] chars) {
278             super();
279             this.chars = chars.clone();
280             Arrays.sort(this.chars);
281         }
282 
283         /**
284          * Returns whether or not the given character matches.
285          *
286          * @param buffer  the text content to match against, do not change
287          * @param pos  the starting position for the match, valid for buffer
288          * @param bufferStart  the first active index in the buffer, valid for buffer
289          * @param bufferEnd  the end index of the active buffer, valid for buffer
290          * @return the number of matching characters, zero for no match
291          */
292         @Override
293         public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
294             return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
295         }
296     }
297 
298     //-----------------------------------------------------------------------
299     /**
300      * Class used to define a character for matching purposes.
301      */
302     static final class CharMatcher extends StrMatcher {
303         /** The character to match. */
304         private final char ch;
305 
306         /**
307          * Constructor that creates a matcher that matches a single character.
308          *
309          * @param ch  the character to match
310          */
311         CharMatcher(final char ch) {
312             super();
313             this.ch = ch;
314         }
315 
316         /**
317          * Returns whether or not the given character matches.
318          *
319          * @param buffer  the text content to match against, do not change
320          * @param pos  the starting position for the match, valid for buffer
321          * @param bufferStart  the first active index in the buffer, valid for buffer
322          * @param bufferEnd  the end index of the active buffer, valid for buffer
323          * @return the number of matching characters, zero for no match
324          */
325         @Override
326         public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
327             return ch == buffer[pos] ? 1 : 0;
328         }
329     }
330 
331     //-----------------------------------------------------------------------
332     /**
333      * Class used to define a set of characters for matching purposes.
334      */
335     static final class StringMatcher extends StrMatcher {
336         /** The string to match, as a character array. */
337         private final char[] chars;
338 
339         /**
340          * Constructor that creates a matcher from a String.
341          *
342          * @param str  the string to match, must not be null
343          */
344         StringMatcher(final String str) {
345             super();
346             chars = str.toCharArray();
347         }
348 
349         /**
350          * Returns whether or not the given text matches the stored string.
351          *
352          * @param buffer  the text content to match against, do not change
353          * @param pos  the starting position for the match, valid for buffer
354          * @param bufferStart  the first active index in the buffer, valid for buffer
355          * @param bufferEnd  the end index of the active buffer, valid for buffer
356          * @return the number of matching characters, zero for no match
357          */
358         @Override
359         public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
360             final int len = chars.length;
361             if (pos + len > bufferEnd) {
362                 return 0;
363             }
364             for (int i = 0; i < chars.length; i++, pos++) {
365                 if (chars[i] != buffer[pos]) {
366                     return 0;
367                 }
368             }
369             return len;
370         }
371     }
372 
373     //-----------------------------------------------------------------------
374     /**
375      * Class used to match no characters.
376      */
377     static final class NoMatcher extends StrMatcher {
378 
379         /**
380          * Constructs a new instance of <code>NoMatcher</code>.
381          */
382         NoMatcher() {
383             super();
384         }
385 
386         /**
387          * Always returns {@code false}.
388          *
389          * @param buffer  the text content to match against, do not change
390          * @param pos  the starting position for the match, valid for buffer
391          * @param bufferStart  the first active index in the buffer, valid for buffer
392          * @param bufferEnd  the end index of the active buffer, valid for buffer
393          * @return the number of matching characters, zero for no match
394          */
395         @Override
396         public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
397             return 0;
398         }
399     }
400 
401     //-----------------------------------------------------------------------
402     /**
403      * Class used to match whitespace as per trim().
404      */
405     static final class TrimMatcher extends StrMatcher {
406 
407         /**
408          * Constructs a new instance of <code>TrimMatcher</code>.
409          */
410         TrimMatcher() {
411             super();
412         }
413 
414         /**
415          * Returns whether or not the given character matches.
416          *
417          * @param buffer  the text content to match against, do not change
418          * @param pos  the starting position for the match, valid for buffer
419          * @param bufferStart  the first active index in the buffer, valid for buffer
420          * @param bufferEnd  the end index of the active buffer, valid for buffer
421          * @return the number of matching characters, zero for no match
422          */
423         @Override
424         public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
425             return buffer[pos] <= ' ' ? 1 : 0;
426         }
427     }
428 
429 }