001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.lookup; 018 019import java.util.Arrays; 020 021import org.apache.logging.log4j.core.helpers.Strings; 022 023/** 024 * A matcher class that can be queried to determine if a character array 025 * portion matches. 026 * <p> 027 * This class comes complete with various factory methods. 028 * If these do not suffice, you can subclass and implement your own matcher. 029 */ 030public abstract class StrMatcher { 031 032 /** 033 * Matches the comma character. 034 */ 035 private static final StrMatcher COMMA_MATCHER = new CharMatcher(','); 036 /** 037 * Matches the tab character. 038 */ 039 private static final StrMatcher TAB_MATCHER = new CharMatcher('\t'); 040 /** 041 * Matches the space character. 042 */ 043 private static final StrMatcher SPACE_MATCHER = new CharMatcher(' '); 044 /** 045 * Matches the same characters as StringTokenizer, 046 * namely space, tab, newline, formfeed. 047 */ 048 private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray()); 049 /** 050 * Matches the String trim() whitespace characters. 051 */ 052 private static final StrMatcher TRIM_MATCHER = new TrimMatcher(); 053 /** 054 * Matches the double quote character. 055 */ 056 private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\''); 057 /** 058 * Matches the double quote character. 059 */ 060 private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"'); 061 /** 062 * Matches the single or double quote character. 063 */ 064 private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray()); 065 /** 066 * Matches no characters. 067 */ 068 private static final StrMatcher NONE_MATCHER = new NoMatcher(); 069 070 /** 071 * Constructor. 072 */ 073 protected StrMatcher() { 074 } 075 076 /** 077 * Returns a matcher which matches the comma character. 078 * 079 * @return a matcher for a comma 080 */ 081 public static StrMatcher commaMatcher() { 082 return COMMA_MATCHER; 083 } 084 085 /** 086 * Returns a matcher which matches the tab character. 087 * 088 * @return a matcher for a tab 089 */ 090 public static StrMatcher tabMatcher() { 091 return TAB_MATCHER; 092 } 093 094 /** 095 * Returns a matcher which matches the space character. 096 * 097 * @return a matcher for a space 098 */ 099 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}